Sigstore replaces long-lived signing keys with short-lived certificates bound to an identity, which removes the key theft problem but makes signature security depend entirely on identity: who can obtain a token for the identity you trust, and whether verifiers actually check that identity. Sigstore now sits under npm provenance, PyPI attestations, container image signing and many release pipelines, so security teams meet it whether or not they chose it. This guide explains how identity and trust work across Cosign, Fulcio and Rekor, who holds privileged roles, how CI workflows and service accounts obtain signing identities, what to log and monitor, and the hardening baseline for both signing and verification. It is for platform, release and supply chain security engineers. For the wider artefact integrity problem see the OWASP CI/CD Top 10 CICD-SEC-9 Improper Artifact Integrity Validation Guide.
Key takeaways
- Keyless means identity-bound, not trust-free. Fulcio issues an X.509 certificate valid for 10 minutes to whoever presents a valid OIDC token, so the OIDC identity and its issuer are what you are really trusting.
- Verification must pin identity and issuer. A signature check that accepts any Sigstore certificate proves only that someone signed; always pass the expected
--certificate-identityand--certificate-oidc-issuer. - CI workflows are the best signers. A GitHub Actions or GitLab CI identity names the repository, workflow and ref, which is far more specific than a personal email address.
- Rekor makes misuse detectable, not impossible. Every signing event is logged publicly, so monitor the log for your identities; detection only works if someone is watching.
- A signature is not a policy. Sigstore's own threat model says a valid signature does not prove the signer should have signed or that the artefact is good; enforcement belongs in admission control and deployment policy.
How identity and access work in Sigstore
Sigstore's documentation describes three roles: the artefact is signed by a client (Cosign or a language client), associated with an identity by the certificate authority (Fulcio) and witnessed in a transparency log (Rekor). Trust in the services' own keys is distributed through a TUF repository.
| Component | Role | What it trusts | Security-relevant detail |
|---|---|---|---|
| Cosign and language clients (JavaScript, Python, Java, Go, Ruby, Rust) | Generate an ephemeral key pair, obtain a certificate, sign, upload to Rekor; verify signatures | The TUF trust root embedded in and refreshed by the client | The private key is discarded after a single signing; Sigstore services never see it |
| Fulcio | Code signing certificate authority | Configured OIDC issuers | Certificates valid for 10 minutes; subject claims from the OIDC token copied into the certificate; issuance logged to a certificate transparency log |
| Rekor | Signature transparency log | Its own signing key | Append-only, verifiable data structure; public instance at rekor.sigstore.dev with a published 99.5 percent availability objective |
| TUF root of trust | Distributes Fulcio, Rekor and CT log verification material | A root established in a public key signing ceremony with a rotation of five keyholders | Provides revocation and rotation for Sigstore's own keys |
| OIDC issuer | Authenticates the signer | Your accounts, CI platform or cluster | The highest-value dependency: compromise of the issuer or account yields valid certificates |
The signing and verification flow
- The client creates an in-memory key pair and obtains an OIDC ID token for the signer (a browser login for a person, an ambient token for a CI job).
- It sends the public key and token to Fulcio, which verifies the token with the issuer and returns a short-lived certificate binding the key to the identity.
- The client signs the artefact digest, records the digest, signature and certificate in Rekor, and receives an inclusion proof and timestamp. Blobs get a bundle file (for example
artifact.sigstore.json); container signatures are stored alongside the image in the registry. - A verifier checks the signature with the certificate's key, checks the certificate chains to the Sigstore root, confirms the identity and issuer match what it expects, and confirms Rekor inclusion at a time when the certificate was valid.
Step 4 is where most deployments are weak. Because anyone with a Google, GitHub or Microsoft account can obtain a Fulcio certificate, a verifier that skips the identity check accepts signatures from attackers too.
Identity values to expect
| Signer | certificate-oidc-issuer | certificate-identity format |
|---|---|---|
| GitHub Actions workflow | https://token.actions.githubusercontent.com | https://github.com/OWNER/REPO/.github/workflows/WORKFLOW@refs/heads/BRANCH (or refs/tags/...) |
| GitLab CI | https://gitlab.com | https://gitlab.com/PROJECT_PATH//CI_CONFIG_PATH@REF_PATH |
| Person via GitHub login | https://github.com/login/oauth | The account's email address, not the username |
| Person via Google | https://accounts.google.com | Email address |
| Person via Microsoft | https://login.microsoftonline.com | Email address |
Fulcio certificates for CI identities also carry extensions under OID 1.3.6.1.4.1.57264.1, including Issuer (V2) (.1.8), Build Signer URI (.1.9), Source Repository URI (.1.12), Source Repository Ref (.1.14), Build Trigger (.1.20), Run Invocation URI (.1.21) and Source Repository Visibility At Signing (.1.22). Policies can match on these to require, for example, a tag ref rather than any branch.
Admin roles and privileged access
Using the public-good instance, you have no administrator account inside Sigstore. Privilege lives in the systems around it:
- OIDC issuer administrators: anyone who can create or take over an identity your policy trusts can sign as it. For CI identities that means repository administrators, anyone who can edit the trusted workflow file, and anyone who can push to the trusted ref.
- Policy owners: whoever can edit verification policy (Kubernetes
ClusterImagePolicyresources, deployment pipeline checks, the identity list in a README) decides what is trusted. Treat policy changes like firewall rule changes, with review. - Admission controller operators: the Sigstore policy controller only validates namespaces labelled
policy.sigstore.dev/include=trueby default, and itsno-match-policysetting decides whether unmatched images are rejected (the default) or merely warned. Cluster administrators who can relabel namespaces or change that ConfigMap can switch enforcement off. - Private deployment operators: if you run your own Fulcio, Rekor and CT log, the CA signing key, the Rekor signing key and the TUF root keys become crown jewels. Keep them in HSMs or cloud KMS, split TUF root keys across several holders, and log every use.
- Key-based signing: Cosign can also sign with a managed key (local file, KMS URI or hardware token). Then key administrators in the KMS hold signing power and the usual key rotation and revocation problems return. See the Code Signing Security Guide.
Integrations, API tokens and service accounts
Sigstore's main integration point is the workload identity of the build. No Sigstore API key exists to steal; what matters is who can obtain the OIDC token.
- GitHub Actions: the job needs
permissions: id-token: write. Grant it only to the signing or release job, not at workflow level, so test jobs running pull request code cannot mint signing tokens. Thecosign-installerandgh-action-sigstore-pythonactions integrate signing. - GitLab CI: request a token with
id_tokens: SIGSTORE_ID_TOKEN: aud: sigstorein the signing job only. - Kubernetes and SPIFFE: Fulcio accepts tokens from configured cluster OIDC issuers and SPIFFE-based issuers, so a workload's service account can sign. Restrict which service accounts can request projected tokens with the right audience. See the Workload Identity Federation Guide.
- Package registries: npm trusted publishing from GitHub Actions or GitLab generates Sigstore-signed provenance automatically, and PyPI accepts PEP 740 attestations signed by trusted publisher identities. The same CI identity rules apply. See the npm Trusted Publishing and Provenance Guide.
- Attestations: Cosign signs in-toto attestations (for example SLSA provenance and SBOMs) as well as artefacts, verified with
cosign verify-attestation. See the in-toto Attestations Guide and the SLSA and Build Provenance Guide. - Private infrastructure: organisations that cannot publish signer identities publicly can run their own stack and distribute a custom trust root, either through their own TUF repository or a trusted root file passed with
--trusted-root.
Choosing a signing mode
- Keyless on the public instance: best default for open source and public images; no keys to rotate, public auditability, but signer identity is published permanently.
- Key-based with KMS: suits air-gapped consumers and verifiers that cannot reach Rekor or TUF; you take back key custody, rotation and revocation work.
- Private Sigstore stack: suits large organisations signing internal artefacts at scale; keeps identities private, at the cost of running a CA, a log and a trust root with the same rigour as any internal PKI.
- Small teams: keyless signing from CI plus identity-pinned verification in one deployment pipeline delivers most of the value without running infrastructure.
Logging and detection
- Identity monitoring in Rekor: the Sigstore threat model says signers should monitor for unauthorised use of their identity. The
rekor-monitorproject provides a reusable GitHub Actions workflow that checks log consistency and can watch for specified identities; alert on any entry for your release identities that does not match a known pipeline run. - Certificate transparency: Fulcio issuance is logged to a CT log; monitoring it shows certificates issued for your identities even if no Rekor entry follows.
- Admission decisions: collect policy controller allow, deny and warn events. A rise in warnings after switching a namespace to warn mode, or any deny in production, needs triage.
- Pipeline logs: keep CI logs showing signing steps, the Rekor log index returned and the artefact digest, so you can match each log entry to a build.
- Issuer side: monitor changes to trusted workflow files, branch protection on release refs and repository admin membership, because those changes alter who can sign.
Metrics:
- Percentage of released artefacts and images signed through a CI identity.
- Percentage of deployments that verify identity and issuer, not just signature presence.
- Rekor entries for your identities with no matching pipeline run (target zero).
- Namespaces enforcing signature policy versus total production namespaces.
- Time to detect a signing event from an unexpected workflow or ref.
Hardening baseline
| Area | Baseline | Why |
|---|---|---|
| Signer identity | Sign releases only from CI workflow identities on protected tags or branches; avoid personal email identities for production artefacts | Workflow identities are specific and auditable; personal accounts are phishable |
| Token scope | id-token: write only on the release job; no untrusted input in that job | Anyone who can run code in that job can sign |
| Verification | Always pin exact identity and issuer; use regular expressions only when anchored and narrow | Unpinned verification accepts any Fulcio certificate |
| Digests | Sign and deploy by digest; let the admission controller resolve tags to digests | Tags are mutable |
| Admission | Enforce in production namespaces with no-match-policy left at reject; use warn only during rollout | Warn mode is not a control |
| Trust root | Let clients refresh the TUF root; for private stacks, distribute your own trusted root through TUF | Allows Sigstore key rotation and revocation to reach verifiers |
| Accounts | Phishing-resistant MFA on every account that administers trusted repositories or the OIDC issuer | The threat model names OIDC account compromise as unmitigated by Sigstore itself |
| Privacy | Use the public instance only for artefacts whose signer identity and repository name may be public permanently | Rekor is an immutable public record |
| Publication | Publish your expected identity and issuer in documentation that only maintainers can change | Consumers cannot verify an identity they do not know |
Rollout
- Sign in CI for one service, publish the expected identity, and verify in the deployment pipeline in report mode.
- Install the policy controller, label a non-production namespace, and run with
no-match-policyset to warn to find unsigned images. - Sign or replace the unsigned images, then switch to reject in that namespace.
- Extend namespace by namespace to production; rollback is relabelling a namespace or reverting a policy, documented in the change plan.
- Add attestations (SLSA provenance, SBOM) and require them in policy for critical services.
Framework mapping
| Framework | Reference | Sigstore control |
|---|---|---|
| NIST SP 800-53 Rev. 5 | SI-7, SI-7(15), CM-14 | Integrity verification, code authentication, signed components at deployment |
| NIST SP 800-53 Rev. 5 | SR-4, SR-11, AU-6 | Provenance, component authenticity, review of transparency log records |
| NIST CSF 2.0 | PR.PS-01, PR.PS-06 | Configuration management and secure development practice |
| MITRE ATT&CK | T1553.002 Code Signing; T1195.002 Compromise Software Supply Chain | Identity-pinned verification blocks artefacts signed by unexpected identities |
Common misconfigurations
- Verifying without identity: checking only that "a valid Sigstore signature exists" accepts signatures any internet user can create.
- Broad identity regular expressions: a pattern matching any workflow in an organisation, or any branch, lets a pull request workflow or feature branch sign production artefacts.
- Workflow-wide
id-token: write: jobs that build untrusted pull request code can mint signing identities. - Trusting the signer to be trustworthy: a stolen CI token or a compromised maintainer account produces genuine signatures. In the Ultralytics PyPI compromise, malicious releases were published through the project's own trusted publishing workflow after a branch name injected code into the build, so provenance would have pointed to the real repository.
- Admission control left in warn mode or opt-in namespaces never labelled: signatures are produced but nothing enforces them.
- Private artefacts on the public log: internal repository names and staff email addresses become permanent public records.
Practitioner checklist
- Sign every release artefact and container image from a CI workflow identity on a protected ref.
- Restrict
id-token: writeor GitLabid_tokensto the release job and keep untrusted code out of it. - Verify with exact
--certificate-identityand--certificate-oidc-issuervalues everywhere artefacts are consumed. - Publish expected signer identities in maintainer-controlled documentation.
- Enforce signature and attestation policy at admission, by digest, with unmatched images rejected in production.
- Monitor Rekor and the CT log for your identities with
rekor-monitoror equivalent. - Require phishing-resistant MFA for administrators of trusted repositories and issuers.
- Run a private Sigstore stack, with HSM-held keys and your own TUF root, for artefacts that must not appear in a public log.
Standards and references
- Sigstore: Overview
- Sigstore: Threat Model
- Sigstore: OIDC Usage in Fulcio
- Sigstore Fulcio: OID information
- Sigstore: Rekor
- Sigstore: Verifying signatures with Cosign
- Sigstore: Kubernetes Policy Controller
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: OWASP CI/CD Top 10 CICD-SEC-9 Improper Artifact Integrity Validation Guide · Code Signing Security Guide · SLSA and Build Provenance Guide · Package Registry Security Comparison Guide