Artifact signing
Artifact signing attaches a cryptographic signature to a release file or container image, so anyone can check who produced it and that its bytes have not changed since. Verification checks that signature against a trust policy naming the identities allowed to sign, before the artifact is installed or deployed.
Between your build and your servers sit registries, mirrors and CDNs, and a tag can be moved to different bytes. Verifying the digest against the expected signer stops a substituted image at deploy time. A signature alone proves little: anyone can make a valid keyless Sigstore signature with their own identity, so the check must also pin who signed, such as your release workflow on main.
- Who
- The release pipeline signs; the platform or SRE team owns the trust policy and the checks at deploy and admission
- When
- Sign in the build job that produced the artifact; verify at promotion, at deploy and when the cluster admits a workload
- How often
- Every release artifact, every time; review the trust policy whenever release workflows, keys or signers change
- You end up with
- A signature or Sigstore bundle per artifact, a written trust policy, and deploy logs showing the verified digest and signer
Do this
Choose a signing method
In CI, keyless signing with Sigstore
cosignavoids a stored key: the job's OIDC token gets a Fulcio certificate valid for 10 minutes, and the signature is recorded in the Rekor transparency log. Notation, from the Notary Project, signs with X.509 certificates checked against a trust store you manage. Either way, sign in the same job that built the artifact.Sign the digest, not a tag
Sign the immutable digest, such as
ghcr.io/acme/api@sha256:..., and later deploy that same digest: a tag can be moved to other bytes. For files, write a Sigstore bundle beside the artifact withcosign sign-blob --bundle, so verifiers get the certificate, signature and log evidence in one file.Write the trust policy
Record which identities may sign which artifacts. For keyless signing that is the exact workflow identity and OIDC issuer, such as
https://github.com/acme/api/.github/workflows/release.yml@refs/heads/mainfromhttps://token.actions.githubusercontent.com; for Notation, a trust store andtrustedIdentities. Keep the policy in protected configuration, not beside the artifact.Verify before every deploy
In the promotion or deploy job, run
cosign verifyon the digest with--certificate-identityand--certificate-oidc-issuer(ornotation verify), and fail on any error. Pin CI claims too where they exist, such as--certificate-github-workflow-trigger push. If you require build provenance, check it in the same step (SBOM and provenance).Enforce the same policy at admission
Anyone who can create Pods directly skips the deploy job, so enforce the identities in the cluster with an admission controller such as Sigstore policy-controller or Kyverno
verifyImages. Policy-controller checks namespaces labeledpolicy.sigstore.dev/include: "true"and, by default, rejects images that match no policy.Test the policy with near misses
Prove the check discriminates: an unsigned image, an image signed by another workflow, the right signer on different bytes and the right identity from another issuer must all be rejected, while the real release passes. Keep these cases as tests of the deploy pipeline.
Publish how to verify, and plan for outages
Publish the verify command and expected identity for your customers: SSDF PS.2.1 asks you to make integrity verification information available to acquirers. Decide in advance what happens when the verifier is down: a recorded, expiring emergency path for one digest, never a silent global bypass.
Done when
The deploy step rejects unsigned artifacts and artifacts signed by an unexpected identity.
Mark it in the gap checkCommon mistakes
- Checking only that an artifact is signed. Anyone can get a valid keyless signature for their own malicious image, so verify the signer's identity and issuer as well.
- Allowing a broad identity, such as any workflow in the organization or an unanchored regular expression. An unrelated repository's workflow can then sign your release; if a pattern is unavoidable, anchor it with
^and$. - Verifying a tag, then deploying the tag. It can move between the two steps, so what runs is not what you checked.
- Reading a valid signature as proof the software is safe. The SolarWinds Orion and 3CX releases were validly signed even though their builds were compromised; add provenance and Pipeline hardening.
- Verifying only in a CI job. A manual push or a direct
kubectl applybypasses it unless admission enforces the same policy. - Keeping a long-lived signing key on build runners or laptops. A stolen key signs anything; OWASP SAMM's top build level keeps signing on a separate server that never exposes the signing certificate.
Keyless, key pair or certificate?
All three can enforce the same rule, that only your release pipeline signs your releases. They differ in what you must protect and what the verifier pins.
| Approach | Signing identity | What the verifier pins |
|---|---|---|
Sigstore keyless (cosign) | A Fulcio certificate valid for 10 minutes, bound to the CI job's OIDC identity | Certificate identity and OIDC issuer, plus CI claims such as trigger and repository |
Key pair (cosign --key) | A long-lived private key you must protect, rotate and be able to revoke | The public key, from a file, a KMS URI or a Kubernetes Secret |
Notary Project (notation) | An X.509 certificate chain from a certificate authority you trust | A trust store and trustedIdentities in a trust policy, scoped to registries |
Tools and guides
- Labs: practice in the browser
- Verify artifact signatures against an explicit trust policy
Require the expected artifact, signer and release context before allowing a signed package or image to proceed.
- Harden container images from Dockerfile to admission
Build minimal, non-root images pinned by digest, keep secrets out of every layer, then scan, sign and verify the exact digest before it runs with dropped privileges.
- Protect package publication and the update channel
Constrain release identities, verify what consumers receive, and prepare for publisher or update-key compromise.
- Read SLSA provenance and verify the claim you need
Connect an artifact to its build evidence while distinguishing provenance, build assurance and source controls.
Standards
- NIST SSDF 1.1
- PS.2 Provide a Mechanism for Verifying Software Release Integrity
- OWASP SAMM 2
- Secure DeploymentSecure Build
Sources
- Sigstore: Verifying signatures
- cosign verify reference
- Sigstore: Certificate authority overview
- Sigstore: Policy controller overview
- Notary Project: Sign and verify a container image with Notation
- Kyverno: Verify images rules
- OWASP SAMM: Secure Deployment, Deployment Process stream
- OWASP SAMM: Secure Build, Build Process stream
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1. February 2022.