Tools · Containers and Kubernetes security · 14 / 20
Signing and verifying container images with Sigstore cosign
Sign an image by digest with cosign, verify it locally, understand keyless signing with OIDC identities, and enforce signatures at admission.
Why sign images
A tag such as myapp:1.4 can be moved to a different image at any time. A signature binds an identity to an image digest, so a cluster can check that the image it is about to run was produced by your pipeline. Sigstore’s cosign stores signatures next to the image in the registry.
Key-based and keyless
With key-based signing you generate a key pair and keep the private key in a KMS or CI secret. With keyless signing, cosign gets a short-lived certificate from Sigstore’s Fulcio CA tied to an OIDC identity, such as a GitHub Actions workflow, and records the signature in the Rekor transparency log. Verification then checks the identity and issuer instead of a public key.
Lab: sign and verify
Run a local registry, push a test image, and sign it by digest with a local key pair. Verify the signature, then push a different image to the same tag and watch verification fail. Signing by digest avoids signing whatever the tag points at later.
docker run -d -p 5000:5000 --name registry registry:2
docker tag alpine:3.20 localhost:5000/demo:1 && docker push localhost:5000/demo:1
DIGEST=$(docker buildx imagetools inspect localhost:5000/demo:1 --format '{{json .Manifest.Digest}}' | tr -d '"')
cosign generate-key-pair
cosign sign --key cosign.key localhost:5000/demo@$DIGEST
cosign verify --key cosign.pub localhost:5000/demo:1
# keyless verification example
cosign verify ghcr.io/org/app:1.4 \
--certificate-identity-regexp 'https://github.com/org/app/.github/workflows/release.yml@.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comEnforcing at admission
Verification only helps if the cluster refuses unsigned images. Kyverno’s verifyImages rules or the Sigstore policy-controller can reject pods whose images lack a valid signature from your identity, and can rewrite tags to digests so the verified image is the one that runs.
Diagram
Signed image lifecycle
- Build
CI builds and pushes the image, capturing the digest.
- Sign
cosign signs the digest with a key or keyless OIDC identity.
- Admit
An admission policy verifies the signature and identity.
- Run
Only verified digests start in the cluster.
Check yourself
1. Why sign by digest rather than by tag?
2. What does keyless signing tie the signature to?
3. How do you make a cluster reject unsigned images?