Stage 5 · Platform
Build, Version & Release
Cosign Signing
Signing container images with Sigstore cosign, keyless OIDC identities, and Rekor transparency logs.
Why Sign Artifacts?
Container images can be tampered with between build and deploy. A compromised registry, a man-in-the-middle attack, or a malicious tag overwrite can inject malicious code into your images. Signing proves that an image was built by your CI pipeline from your source code.
Sigstore is a set of tools for signing, verifying, and protecting software supply chains. Cosign is the Sigstore tool for signing container images and other artifacts. It supports both traditional key-based signing and keyless OIDC-based signing.
Sigstore Overview
| Component | Purpose |
|---|---|
| Cosign | Sign and verify container images and artifacts |
| Fulcio | Issue short-lived certificates for OIDC identities |
| Rekor | Append-only transparency log for signatures |
| _OIDC Provider_ | GitHub, Google, SAML identity providers |
Cosign in CI
jobs:
build-and-sign:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- name: Install cosign
uses: sigstore/cosign-installer@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:
context: .
push: true
tags: ghcr.io/myorg/myapp:${{ github.sha }}
- name: Sign the image
run: |
cosign sign --yes ghcr.io/myorg/myapp:${{ github.sha }}
- name: Attach SBOM
run: |
syft dir:. -o cyclonedx-json=sbom.json
cosign attach sbom --sbom sbom.json ghcr.io/myorg/myapp:${{ github.sha }}
- name: Attach attestation
run: |
cosign attest --yes \
--predicate provenance.json \
--type slsaprovenance \
ghcr.io/myorg/myapp:${{ github.sha }}cosign sign uses keyless signing by default — it obtains a short-lived certificate from Fulcio using the GitHub OIDC identity. --yes confirms the transparent log upload to Rekor. No keys need to be managed.
Keyless Signing
Keyless signing eliminates the need to manage signing keys. Instead of storing private keys in secrets, cosign uses your CI platform's OIDC identity. Fulcio issues a short-lived certificate that links the signature to your GitHub Actions workflow.
jobs:
sign:
runs-on: ubuntu-latest
permissions:
id-token: write
packages: write
steps:
- uses: sigstore/cosign-installer@v3
- name: Sign with keyless identity
run: |
cosign sign --yes \
--certificate-identity=https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/myorg/myapp:${{ github.sha }}The certificate-identity specifies the exact workflow that signed the image. The certificate-oidc-issuer is GitHub's OIDC provider. This creates a cryptographic chain: the signature is valid only if the image was signed by the specified workflow.
Verifying Signatures
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: sigstore/cosign-installer@v3
- name: Verify signature
run: |
cosign verify \
--certificate-identity=https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/myorg/myapp:${{ github.sha }}
- name: Verify SBOM
run: |
cosign verify-attestation \
--type cyclonedx \
--certificate-identity=https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/myorg/myapp:${{ github.sha }}
- name: Deploy
run: kubectl set image deployment/myapp myapp=ghcr.io/myorg/myapp:${{ github.sha }}Verification checks that the signature is valid, the certificate was issued by the expected OIDC provider, and the identity matches the expected workflow. This prevents deployment of images built by unauthorized pipelines.
Rekor Transparency Log
Rekor is an append-only transparency log that records every signature. Once a signature is logged, it cannot be removed or modified. This provides an audit trail of all signing events and prevents backdated signatures.
# Look up signatures by image digest
cosign verify \
--certificate-identity=... \
--certificate-oidc-issuer=... \
ghcr.io/myorg/myapp:abc123
# Search Rekor by image reference
rekor-cli search --rekor https://rekor.sigstore.dev \
--image ghcr.io/myorg/myapp
# Get signature details
rekor-cli get --rekor https://rekor.sigstore.dev \
--log-index <LOG_INDEX>Rekor provides cryptographic proof that a signature existed at a specific time. If a vulnerability is discovered in a signed image, you can use Rekor to determine exactly when it was signed and by which identity.
Configure your Kubernetes admission controller to reject unsigned images. Kyverno's verifyImages policy and Gatekeeper's ConstraintTemplate for cosign verification prevent untrusted images from being deployed to your cluster.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.