Cyber Intelligence
Supply Chain and Image Security · Supply chain

L15. Image Signing and Verification with Cosign and Sigstore

Video generating

Check back soon for the video lesson on Image Signing and Verification with Cosign and Sigstore

Image scanning tells you what is wrong with an image. Image signing tells you whether an image is trustworthy. Learn how to sign images with Cosign and verify signatures at admission time.

Why Sign Images?

Scanning detects known vulnerabilities. Signing proves provenance: this image was built by your pipeline, from your source code, and has not been tampered with. Without signing, an attacker who compromises your registry can replace images with malicious versions.

The Sigstore Ecosystem

Sigstore is an open-source project that provides free code signing infrastructure:

ComponentPurpose
CosignSigns and verifies container images
FulcioIssues short-lived signing certificates (no key management)
RekorTransparency log that records all signing events

Signing with Cosign

Key-based signing (self-managed keys):
# Generate a keypair
cosign generate-key-pair

# Sign an image cosign sign --key cosign.key myregistry.io/myapp:v1.0

# Verify a signature cosign verify --key cosign.pub myregistry.io/myapp:v1.0

Keyless signing (recommended for CI/CD):
cosign sign myregistry.io/myapp:v1.0

In keyless mode, Cosign uses Fulcio to issue a short-lived certificate based on your OIDC identity (GitHub Actions, GitLab CI, Google). The signing event is recorded in Rekor's transparency log. No keys to manage, rotate, or protect.

CI/CD Integration

Sign images in your build pipeline after scanning passes:

# GitHub Actions
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">name: Sign image</li>
</ul>
  env:
    COSIGN_EXPERIMENTAL: "1"
  run: |
    cosign sign myregistry.io/myapp:${{ github.sha }} \
      -a "repo=${{ github.repository }}" \
      -a "workflow=${{ github.workflow }}" \
      -a "commit=${{ github.sha }}"

Annotations (-a) attach metadata like the source repo, workflow name, and commit SHA to the signature for audit purposes.

Verification at Admission

Use the Sigstore Policy Controller or Kyverno to verify signatures before pods are created:

apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signing
spec:
  images:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">glob: "myregistry.io/**"</li>
</ul>
  authorities:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">keyless:</li>
</ul>
        url: https://fulcio.sigstore.dev
        identities:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">issuer: https://token.actions.githubusercontent.com</li>
</ul>
            subject: "https://github.com/myorg/myapp/.github/workflows/build.yml@refs/heads/main"

This policy requires that all images from myregistry.io are signed by a specific GitHub Actions workflow running on the main branch. Images signed from a fork or a different branch are rejected.

Software Bill of Materials (SBOM)

Cosign can also attach SBOMs to images:

# Generate SBOM
trivy image --format spdx-json myapp:v1.0 > sbom.json

# Attach to image cosign attach sbom --sbom sbom.json myregistry.io/myapp:v1.0

SBOMs provide a complete inventory of software components in the image, enabling vulnerability tracking over the image's lifetime.

Exam Focus Points
  • Scanning detects known vulnerabilities; signing proves provenance and integrity of the image
  • Keyless signing with Fulcio uses OIDC identity (GitHub Actions, GitLab CI) and eliminates key management
  • Rekor transparency logs provide a tamper-proof record of all signing events
  • Sigstore Policy Controller and Kyverno can verify image signatures at admission time before pods are created
  • SBOMs attached to images with Cosign provide a complete software inventory for lifecycle vulnerability tracking
Knowledge Check

1. What problem does image signing solve that image scanning does not?

2. What is the advantage of keyless signing with Cosign and Fulcio?

3. How can you ensure that only images built from your main branch are deployed?