Cosign/Sigstore Reference: Sign Container Images, Keyless OIDC, SBOMs & K8s Policy Enforcement
Cosign (part of Sigstore) signs container images and other OCI artifacts, giving you cryptographic proof that an image was built by your pipeline and hasn’t been tampered with. It’s now the default signing tool in most supply chain security frameworks including SLSA, CNCF projects, and GitHub’s Artifact Attestations.
1. Cosign Concepts & Install
What Cosign signs, how signatures work, and install
| Method | Key storage | Best for |
|---|---|---|
| Key-pair signing | cosign.key / cosign.pub | Simple, self-managed PKI |
| Keyless (OIDC) | Fulcio CA + Rekor transparency log | CI/CD — no key management |
| KMS-backed | AWS KMS / GCP KMS / Vault | Enterprise — HSM-backed keys |
# Install: brew install cosign # macOS # Or: https://github.com/sigstore/cosign/releases (single binary) # Keyless signing uses your OIDC identity (GitHub Actions, Google, etc.) # No key to generate, store, or rotate # Signature is anchored to your GitHub/Google identity + time via Fulcio + Rekor # Key-pair signing (traditional): cosign generate-key-pair # creates cosign.key (encrypted) + cosign.pub # Set COSIGN_PASSWORD env var to avoid interactive prompt in CI: COSIGN_PASSWORD=my-pass cosign generate-key-pair
2. Sign & Verify Images
Sign after build, verify before deploy
# Sign with key-pair (after docker push):
cosign sign --key cosign.key ghcr.io/my-org/my-app:v1.2.3
# Sign with OIDC keyless (in CI — uses GitHub Actions OIDC token automatically):
cosign sign ghcr.io/my-org/my-app:v1.2.3
# No --key needed — Fulcio issues a short-lived cert tied to github.com/my-org/my-app
# Sign by digest (more stable than tag — tags can be rewritten):
IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' my-app:v1.2.3)
cosign sign --key cosign.key $IMAGE_DIGEST
# Verify with public key:
cosign verify --key cosign.pub ghcr.io/my-org/my-app:v1.2.3
# Verify keyless (check identity claims):
cosign verify --certificate-identity-regexp "https://github.com/my-org/my-app/.github/workflows/.*" --certificate-oidc-issuer https://token.actions.githubusercontent.com ghcr.io/my-org/my-app:v1.2.3
# Verify output shows:
# [{"critical":{"identity":{"docker-reference":"ghcr.io/my-org/my-app"},...}}]
# If verification FAILS, cosign exits non-zero — use this in admission webhooks
3. GitHub Actions — Sign on Every Build
Full CI workflow: build, push, sign with keyless OIDC
# .github/workflows/build-sign.yml
name: Build, Push, Sign
on:
push:
branches: [main]
tags: ['v*']
jobs:
build-sign:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # REQUIRED for keyless OIDC signing
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
# Capture the digest for signing:
outputs: type=image,push=true
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Sign image (keyless)
run: |
cosign sign --yes ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
# --yes skips interactive prompt in CI
# Signature goes to Rekor public transparency log
- name: Verify immediately
run: |
cosign verify --certificate-identity-regexp "https://github.com/${{ github.repository }}/.github/workflows/.*" --certificate-oidc-issuer https://token.actions.githubusercontent.com ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
4. Attach & Verify SBOMs
Sign and attach Software Bill of Materials (SBOM) to images
# Generate SBOM with Syft: brew install syft syft ghcr.io/my-org/my-app:v1.2.3 -o cyclonedx-json > sbom.json # Attach the SBOM to the image as an OCI attestation: cosign attach sbom --sbom sbom.json ghcr.io/my-org/my-app:v1.2.3 # Or use attest (signs + attaches in one step): cosign attest --predicate sbom.json --type cyclonedx --key cosign.key ghcr.io/my-org/my-app:v1.2.3 # Verify the attestation: cosign verify-attestation --type cyclonedx --key cosign.pub ghcr.io/my-org/my-app:v1.2.3 | jq '.payload | @base64d | fromjson | .predicate' # In-Toto provenance (SLSA): cosign attest --predicate provenance.json --type slsaprovenance ghcr.io/my-org/my-app:v1.2.3
5. Policy Enforcement with Kyverno or Connaisseur
Enforce signature verification at admission time in Kubernetes
# Kyverno — require signed images in production namespace:
# (Kyverno 1.10+ has native Sigstore/Cosign support)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
rules:
- name: check-image-signature
match:
any:
- resources:
kinds: [Pod]
namespaces: [production]
verifyImages:
- imageReferences:
- "ghcr.io/my-org/*" # match our images
attestors:
- entries:
- keyless:
subject: "https://github.com/my-org/*/.github/workflows/*"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: https://rekor.sigstore.dev
# Any pod in 'production' that uses an unsigned image from ghcr.io/my-org/
# will be rejected by the admission webhook.
# Quick manual enforcement (admission not set up yet):
# Verify in your deployment pipeline before kubectl apply:
cosign verify --key cosign.pub $IMAGE_REF || { echo "Image unsigned, aborting"; exit 1; }
kubectl apply -f deployment.yaml
Track Cosign, Sigstore, and supply chain security tool releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: Trivy Reference | Kyverno Reference | GitHub Actions Reference
🔍 Free tool: K8s YAML Security Linter — complement cosign image signing by also checking your K8s manifests for 12 security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com