Stage 4 · Provision
Registries & Security
Image Signing
Sign and verify container images with Sigstore Cosign, keyless signing, attestations, and Rekor.
Why Sign Images?
Image tags are mutable — they can be overwritten. Without signing, an attacker could push a malicious image with the same tag as your trusted image. Image signing provides cryptographic proof that an image was built by you and has not been tampered with.
Cosign Basics
Cosign is part of the Sigstore project. It signs container images and stores signatures alongside the image in the registry. Cosign signatures are stored as separate tags, not embedded in the image.
# Install Cosign
brew install cosign # macOS
# Generate a key pair
cosign generate-key-pair
# Sign an image
cosign sign --key cosign.key myregistry.com/myapp:1.0
# Verify a signature
cosign verify --key cosign.pub myregistry.com/myapp:1.0
# List signatures
cosign list myregistry.com/myapp:1.0Cosign generates a private key (cosign.key) for signing and a public key (cosign.pub) for verification. Keep the private key secure. Share the public key with consumers of your images.
Keyless Signing
Keyless signing uses ephemeral keys backed by OIDC identity (GitHub Actions, Google, etc.). No long-lived keys to manage. Cosign generates a temporary key, signs the image, and stores the signature with your identity in the Rekor transparency log.
# Sign without managing keys (uses OIDC)
cosign sign myregistry.com/myapp:1.0
# Verify keyless signature
cosign verify \
--certificate-identity=user@example.com \
--certificate-oidc-issuer=https://accounts.google.com \
myregistry.com/myapp:1.0
# In GitHub Actions, identity is the workflow
cosign verify \
--certificate-identity=https://github.com/org/repo/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
myregistry.com/myapp:1.0Keyless signing is simpler and more secure than key-based signing. No keys to rotate or store. Your identity is verified through OIDC providers. Signatures are logged in Rekor for auditability.
Every Cosign signature is recorded in Rekor, a tamper-proof transparency log. You can verify that a signature exists and was not added after the fact. This prevents signature backdating and provides an audit trail.
Verifying Signatures
# Verify with a public key
cosign verify --key cosign.pub myregistry.com/myapp:1.0
# Verify keyless with identity
cosign verify \
--certificate-identity=build@project.iam.gserviceaccount.com \
--certificate-oidc-issuer=https://accounts.google.com \
myregistry.com/myapp:1.0
# Verify in a script (fails on verification failure)
if cosign verify --key cosign.pub myregistry.com/myapp:1.0; then
echo "Image verified"
docker pull myregistry.com/myapp:1.0
else
echo "Image signature invalid"
exit 1
fiVerification checks the signature against the public key or OIDC identity. If the image was modified after signing, verification fails. Use this in deployment pipelines before pulling images.
Attestations
Attestations are signed metadata about how an image was built. They can include build provenance (SLSA), vulnerability scan results, test results, or SBOMs. Consumers verify attestations to ensure the image meets their security requirements.
# Create a vulnerability scan attestation
trivy image --format cyclonedx myapp:1.0 > sbom.json
cosign attest --key cosign.key --predicate sbom.json \
--type cyclonedx myapp:1.0
# Verify the attestation
cosign verify-attestation --key cosign.pub \
--type cyclonedx myapp:1.0
# Create a SLSA provenance attestation
cosign attest --key cosign.key --predicate provenance.json \
--type slsaprovenance myapp:1.0Attestations prove that your image was scanned, tested, and built correctly. Use them to enforce compliance — for example, reject images without a valid SBOM attestation.
Enforcement
Signing is only useful if you verify. Configure your deployment pipeline, Kubernetes admission controller, or registry to reject unsigned images. This prevents unverified images from reaching production.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signatures
spec:
validationFailureAction: Enforce
rules:
- name: check-image-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "myregistry.com/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----Kyverno is a Kubernetes policy engine. This policy enforces that all images from myregistry.com have valid Cosign signatures. Pods with unsigned images are rejected.
Sign images during CI/CD build and push. Verify signatures during deployment. This ensures only images built by your pipeline reach production. Cosign keyless signing is ideal for CI/CD — no key management required.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.