sigstore/fulcio

repository·main·Indexed 21 days ago

https://github.com/sigstore/fulcio

A free-to-use Certificate Authority (CA) that issues short-lived (10-minute) code signing certificates based on OpenID Connect (OIDC) identities. Fulcio provides an API accessible via HTTP and gRPC, publishes issued certificates to a Certificate Transparency (CT) log for auditability, and supports multiple CA backends including Google Cloud Private CA, Tink, PKCS#11, and Cloud KMS.

Tokens
29.7K
Snippets
55
Records
90
Agent score
74%

What's inside Fulcio

  1. What is Certificate Maker?

    main
    Certificate Maker is a tool used to create X.509 certificates (root, intermediate, and leaf) that comply with Fulcio's certificate requirements. It generates certificates from JSON templates using Go standard library template parsing and JSON unmarshaling. The tool comes with embedded default templates, allowing it to function without requiring external template files.
  2. What is Fulcio

    main

    Fulcio is a free-to-use Certificate Authority (CA) designed for issuing short-lived code signing certificates. It issues certificates based on an OpenID Connect (OIDC) identity (such as an email address).

    Key Characteristic: Fulcio only issues certificates that are valid for 10 minutes.

  3. Identify Beta features in Fulcio

    main

    The following features are currently in Beta and are subject to change according to the Sigstore API Stability Policy. Use these with caution in production environments:

    • Fulcio API: The core API interface.
    • Certificate Authority (CA) Support: Support for various backends including Google Private CA Service, PKCS11, and File-backed CA.
    • Challenge Support: Support for SPIFFE challenges and OIDC-based email challenges.
    • Go Client Library: The client library located in fulcio/pkg.
    • Issuers: Configuration for issuers as defined in fulcio-config.yaml.
  4. How to pick a Subject Alternative Name (SAN)

    main

    SANs are used in verification policies as the primary identifier for a workload. When choosing a SAN for your service, consider these criteria:

    • Policy Queryability: How will users want to write policies? A good test is whether the value works well with cosign verify --certificate-identity=<VALUE>.
    • Specificity: Choose the most specific identifier that describes the workload without being too broad (granting unintended access) or too narrow (making management difficult).
    • Stability: Avoid identifiers that change per instance (like UUIDs). If a policy requires a regex to match a SAN, the SAN is likely too specific.
    • Uniqueness: SANs should be unique to the issuer and prevent one resource from spoofing another.
    • Documentation: All SANs produced by a provider should be well-defined and documented.

    Case Study: GitHub Actions

    GitHub Actions uses job_workflow_ref as its SAN. This is preferred over other options because:

    • It is tied to a specific Job in a workflow.
    • It supports reusable workflows, allowing centralized policies.
    • It is more stable than a unique Job ID (which changes every run) and more specific than a Repository URL (which is too broad).
  5. How Fulcio certificate issuance works

    main

    Fulcio issues code signing certificates by verifying an OpenID Connect (OIDC) identity and proving possession of a private key. The process follows these steps:

    1. Certificate Request Input: The client submits an OIDC identity token (JWT), a public key, and a signed challenge (a signature of the sub claim from the OIDC token). Alternatively, a Certificate Signing Request (CSR) can be provided.
    2. Authentication: Fulcio authenticates the OIDC token by using the iss (issuer) claim to find the issuer's discovery endpoint, downloading their signing keys, and verifying the token signature.
    3. Verifying the Challenge: Fulcio verifies that the client owns the private key corresponding to the provided public key by validating the signed challenge or the CSR.
    4. Constructing the Certificate: Fulcio creates an X.509 certificate containing the client's public key, sets the Subject Alternative Name (SAN) to the OIDC sub claim (e.g., email, SPIFFE ID, or GitHub Actions identity), and includes the OIDC issuer in a custom field.
    5. Signing: The certificate is signed by a Certificate Authority (CA) backend to create a chain of trust.
    6. CT Log Inclusion: The certificate is sent to a Certificate Transparency (CT) log as a precertificate. The log returns a Signed Certificate Timestamp (SCT), which is embedded in the certificate before a final signature.
    7. Delivery: The final certificate containing the embedded SCT is returned to the client.
  6. Understand Signed Certificate Timestamps (SCT) in Fulcio

    main

    Fulcio maintains a Certificate Transparency (CT) log using Trillian to ensure all issued certificates are publicly verifiable.

    A Signed Certificate Timestamp (SCT) is a cryptographic promise from the CT server that a certificate entry will be included in the log within a fixed timeframe.

    SCTs are handled in two ways:

    1. Detached SCTs: Fulcio returns the SCT alongside the certificate. The caller (e.g., Cosign) is responsible for storing it. If the caller does not store the SCT, it cannot be verified later.
    2. Embedded SCTs: The SCT is included directly within a certificate extension. This is the preferred method for long-term verification because the SCT travels with the certificate.

    All Fulcio signing backends support detached SCTs, but support for embedded SCTs is optional per backend.

  7. How Fulcio's security model works

    main

    Fulcio's security model is built on the assumption that a valid OIDC token provides sufficient proof of ownership for an email address. To mitigate the risk of OIDC provider compromise or malicious CA behavior, Fulcio uses a transparency-based model:

    1. Mandatory Logging: Fulcio must publish all issued certificates to an immutable, append-only, cryptographically verifiable transparency log (Rekor).
    2. Client Verification: Clients must not trust any certificate that is not present in the transparency log.
    3. Detection: This mechanism allows users to detect mis-issued certificates. When combined with Rekor's signature transparency, artifacts signed with compromised accounts can be identified.

    This approach shifts the security focus from preventing issuance to ensuring visibility and auditability.

  8. Configure Certificate Transparency (CT) Log support

    main

    All signing backends can be configured to write issued certificates to a transparency log. When configured, Signed Certificate Timestamps (SCTs) are returned in a custom HTTP header or gRPC field.

    Embedded SCTs: Currently, only the KMS and File-based signing backends support embedded SCTs. Using embedded SCTs is recommended because clients can verify proof of inclusion directly from the certificate without needing to store a detached SCT.

  9. Reuse existing certificates in a hierarchy

    main

    To maintain a stable certificate chain (e.g., keeping a long-lived Root CA while rotating Leaf certificates), use the --existing-root-cert and --existing-intermediate-cert flags (or EXISTING_ROOT_CERT and EXISTING_INTERMEDIATE_CERT environment variables).

    Decision Logic for Reuse

    • Fresh Start: Generate all (Root + Intermediate + Leaf).
    • Keep Root, Rotate Intermediate/Leaf: Use --existing-root-cert. This generates a new intermediate and leaf signed by the existing root.
    • Keep Root & Intermediate, Rotate Leaf: Use --existing-root-cert AND --existing-intermediate-cert. This generates only a new leaf.
    • Direct Leaf from Root: Use --existing-root-cert but do NOT provide an intermediate key ID. This generates a leaf signed directly by the root.

    Important Constraints:

    • The existing certificate's public key MUST match the KMS key specified. The tool validates this match before proceeding.
    • --template flags and --existing-...-cert flags are mutually exclusive for the same certificate tier.
    # Example: Reuse Root and Intermediate to generate a new Leaf only (GCP KMS)
    ./certificate-maker create "https://fulcio.example.com" \
      --kms-type gcpkms \
      --gcp-credentials-file ~/.config/gcloud/application_default_credentials.json \
      --root-key-id projects/<project>/locations/<loc>/keyRings/<ring>/cryptoKeys/root/cryptoKeyVersions/1 \
      --existing-root-cert ./existing-root.pem \
      --intermediate-key-id projects/<project>/locations/<loc>/keyRings/<ring>/cryptoKeys/intermediate/cryptoKeyVersions/1 \
      --existing-intermediate-cert ./existing-intermediate.pem \
      --leaf-key-id projects/<project>/locations/<loc>/keyRings/<ring>/cryptoKeys/leaf/cryptoKeyVersions/1 \
      --leaf-cert leaf.pem
  10. Sigstore OID extension formats

    main

    Fulcio uses the Sigstore Private Enterprise Number (1.3.6.1.4.1.57264) to organize metadata in certificates. The encoding format of these extensions varies depending on the OID:

    • Raw Strings: OIDs 1.3.6.1.4.1.57264.1.1 through 1.3.6.1.4.1.57264.1.6 are formatted as raw strings without DER encoding.
    • OtherName SAN: OID 1.3.6.1.4.1.57264.1.7 is a DER-encoded string in the SubjectAlternativeName extension (per RFC 5280 4.2.1.6).
    • DER-encoded UTF8Strings: OIDs 1.3.6.1.4.1.57264.1.8 through 1.3.6.1.4.1.57264.1.24 are DER-encoded strings using the UTF8String (0x0C) ASN.1 tag.
  11. How Fulcio uses OIDC tokens

    main

    Fulcio uses OpenID Connect (OIDC) tokens to authenticate requests. During the authentication process, Fulcio extracts subject-related claims from the provided OIDC token and includes them in the issued certificates as Subject Alternative Names (SANs).

    Sigstore typically runs a federated OIDC identity provider called Dex. In this flow, users authenticate to their preferred identity provider (e.g., Google, GitHub), and Dex generates a new OIDC token containing claims derived from the original provider's token. Fulcio can also be configured to support OIDC tokens from additional, explicitly configured issuers.

  12. OIDC requirements for URI and Username identities

    main

    Fulcio supports identities based on URIs or plain usernames, requiring a SubjectDomain in the Fulcio configuration.

    URI Identity

    • Token Claim: sub must be a URI (e.g., https://example.com/users/1).
    • Constraint: The domain of the sub claim must match the SubjectDomain configuration exactly. The issuer must partially match the domain (scheme, TLD, and second-level domain).
    • Result: sub is included as a SAN URI.

    Username Identity

    • Token Claim: sub is a username (e.g., exampleUsername).
    • Constraint: The issuer must partially match the domain (TLD and second-level domain). The SubjectDomain is appended to sub to form the identity: sub!SubjectDomain (e.g., exampleUsername!example.com), which is included as an OtherName SAN.
    // URI Example
    {
        "sub": "https://example.com/users/1"
    }
    
    // Username Example
    {
        "sub": "exampleUsername"
    }