Image Signing and SBOM with Cosign and Syft
AI generated
FROM
RUN
Docker · Cosign · SBOM · Supply Chain Security
Image Signing and SBOM Basics
cryptographically proving origin and content of Docker images

Image signing proves that a container image actually originates from your own pipeline and has not been altered since the build. A software bill of materials lists every single component inside the image and makes supply chain risks visible before they turn into a security incident. Cosign and Syft from the Sigstore ecosystem implement both without requiring your own PKI infrastructure.

19 min read Cosign · Syft · Sigstore · SBOM Supply Chain Security · CI/CD

1. Why image signing and SBOM belong together

Image signing answers the question of whether a container image actually comes from a trusted source and has remained unchanged since the build. An SBOM, the software bill of materials, answers a different question: which packages, libraries and versions the image actually consists of. Both concepts address different risks in the supply chain and complement rather than replace each other.

Without image signing, an attacker who gains access to a registry can substitute a manipulated image under the same tag without deployment processes noticing. Without an SBOM, nobody on the team knows which version of OpenSSL or which transitive Composer dependencies are actually running inside the production container when a new critical CVE goes public. Incidents such as the SolarWinds attack and the Log4Shell vulnerability turned both topics from a niche concern into a regulatory requirement, for example under the EU Cyber Resilience Act and Executive Order 14028 in the United States.

The Sigstore project, originally initiated by Google, Red Hat and the Linux Foundation, provides Cosign as the standard tool for image signing without your own public key infrastructure, while Syft from Anchore is the most widely used tool for generating an SBOM from container images. Together they form the foundation of modern supply chain security for Docker workflows.

2. Cosign: fundamentals of image signing

Cosign signs a container image by generating a cryptographic signature over the image digest, not the tag, and storing it as a separate OCI artifact next to the image in the same registry. The digest is crucial because tags are mutable, an attacker could point the same tag to a different digest. The signature binds to the immutable SHA256 digest of the manifest and makes any later manipulation detectable.

The classic approach with a private key pair requires teams to store the private key securely, for example in a hardware security module or a secrets manager such as HashiCorp Vault. Cosign supports both local key files and cloud KMS integrations with AWS, GCP and Azure, which means the key itself never sits on the CI runner's disk in plain text.


# Generate a local key pair for image signing (protected by a passphrase)
cosign generate-key-pair
# Produces cosign.key (private, encrypted) and cosign.pub (public)

# Sign an image by its digest, not by its mutable tag
cosign sign --key cosign.key \
  registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

# Verify the signature against the public key before deployment
cosign verify --key cosign.pub \
  registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

3. Keyless signing with Sigstore and OIDC

The real distinguishing feature of Cosign is keyless signing, which replaces classic key management with short lived certificates. Instead of a long lived private key, the CI runner authenticates via an OIDC token, for example through the native GitHub Actions or GitLab CI identity, against Fulcio, the Sigstore certificate authority. Fulcio issues a certificate valid for a few minutes, which is used to create the signature, and logs the entire process immutably in the transparent Rekor log.

The advantage over classic image signing: there is no more long lived private key that an attacker could steal. The chain of trust is instead based on the identity of the CI system itself, verifiable through the public Rekor transparency log, which anyone can inspect without Mironsoft or a customer having to run their own certificate infrastructure.


# Keyless signing: authenticates via OIDC (e.g. GitHub Actions identity)
# No private key file needed, Fulcio issues a short-lived certificate
cosign sign registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

# Verify keyless signature, checking issuer and expected identity
cosign verify \
  --certificate-identity="https://github.com/mironsoft/shop-app/.github/workflows/build.yml@refs/heads/main" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

4. Syft: generating an SBOM from an image

Syft analyzes the layers of a container image and detects installed operating system packages, Composer dependencies, npm packages, Python wheels and dozens of other package ecosystems inside it, entirely without access to the original source code or build process. The result is a complete SBOM that lists every detected component with its exact version number and originating layer.

For PHP projects, Syft detects both composer.lock entries and actually installed package files in the vendor directory, which reveals discrepancies between declared and actually shipped dependencies. This ability to analyze directly from the finished image rather than from source files makes Syft the preferred tool for generating an SBOM retroactively for already built images.


# Generate an SBOM directly from a built image, in SPDX JSON format
syft registry.mironsoft.de/shop-app@sha256:3f29a1c8b7... \
  -o spdx-json > shop-app-sbom.spdx.json

# List detected package ecosystems in a human readable table
syft registry.mironsoft.de/shop-app:1.4.0 -o table

# Example output includes rows like:
#   NAME              VERSION   TYPE
#   symfony/console   7.1.0     php-composer
#   openssl           3.0.13    deb

5. SBOM formats: SPDX and CycloneDX compared

Two competing formats, both backed by major standardization bodies, have established themselves for SBOM documents. SPDX, maintained by the Linux Foundation, originally comes from the license compliance world and has since been standardized as ISO/IEC 5962. CycloneDX, developed by OWASP, was built from the start for security use cases such as vulnerability correlation and includes additional fields for vulnerability references directly inside the document.

Syft supports both formats natively through simple output flags, so the choice usually depends on the requirements of downstream tools, for example whether a scanner or compliance platform expects a specific format. For regulatory requirements in the EU, SPDX is increasingly referenced, while many security tools such as Grype natively prefer CycloneDX.

6. Attestations: SBOM as a signed attachment on the image

An unsigned SBOM file alone is of little value, because it could be altered afterwards without anyone noticing. Cosign solves this problem by linking the SBOM to the image digest as an in-toto attestation and signing it. Like the signature itself, this attestation is stored as an OCI artifact in the registry next to the image and can be pulled and verified together with the image.

The advantage of this linkage: anyone pulling the image can verify both the origin through image signing and the exact content through the signed SBOM attestation in a single step, without having to manage or manually match separate files.


# Attach a signed SBOM attestation to the image digest
cosign attest --predicate shop-app-sbom.spdx.json \
  --type spdxjson \
  --key cosign.key \
  registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

# Download and verify the attached SBOM attestation
cosign verify-attestation --key cosign.pub \
  --type spdxjson \
  registry.mironsoft.de/shop-app@sha256:3f29a1c8b7...

7. Enforcing verification: policy controllers in Kubernetes

Signing alone brings no security benefit if nobody actually checks the signature at deployment time. In Kubernetes environments, the Sigstore policy controller handles this task as an admission webhook, intercepting every new pod start and verifying the referenced image against a stored policy before the scheduler starts the pod at all. If a valid signature is missing or the identity does not match the expected pipeline, the pod start is rejected.

This enforced verification closes the gap between the mere presence of a signature and its actual enforcement. Without a policy controller, image signing remains a purely documentary measure, with a policy controller it becomes an active control that technically prevents compromised or unauthorized images from reaching production.

8. CI pipeline: build, sign, attach SBOM

In a complete CI pipeline, build, signing and SBOM generation run as consecutive steps immediately after the push to the registry. Order and automation matter here: a manual intermediate step where a developer signs the image locally contradicts the very idea of keyless signing, which specifically relies on the verifiable identity of the automated CI system.

It is also important to define the pipeline's fail behavior: a build without a valid signature or without a generated SBOM should block the deployment step instead of merely logging a warning, otherwise the control remains purely cosmetic.


# GitHub Actions: build, sign keyless, attach SBOM as attestation
build-sign-sbom:
  runs-on: ubuntu-latest
  permissions:
    id-token: write   # required for keyless OIDC signing
    contents: read
  steps:
    - uses: actions/checkout@v4
    - name: Build and push image
      run: |
        docker build -t registry.mironsoft.de/shop-app:${{ github.sha }} .
        docker push registry.mironsoft.de/shop-app:${{ github.sha }}
    - name: Sign image keyless
      run: cosign sign --yes registry.mironsoft.de/shop-app:${{ github.sha }}
    - name: Generate SBOM with Syft
      run: syft registry.mironsoft.de/shop-app:${{ github.sha }} -o spdx-json > sbom.json
    - name: Attach signed SBOM attestation
      run: cosign attest --yes --predicate sbom.json --type spdxjson \
        registry.mironsoft.de/shop-app:${{ github.sha }}

9. Signing methods and SBOM formats compared

The choice between classic key based signing and keyless signing, as well as between SPDX and CycloneDX for the SBOM, depends on organizational and regulatory constraints. The following table compares the most relevant options.

Criterion Key Based Keyless (Sigstore)
Key management Needed, HSM or Vault recommended Not needed at all
Trust basis Private key OIDC identity plus Rekor log
Offline capability Yes No, an OIDC provider is required
Transparency log Optional Mandatory, publicly viewable
SBOM format recommendation SPDX for compliance CycloneDX for vulnerability correlation

For most new CI pipelines, keyless signing is the more pragmatic default, because no private key ever needs to be rotated, secured, or accidentally leaked. Air gapped environments without internet access to the public Fulcio and Rekor services, however, still need classic key based signing or a private Sigstore instance.

Mironsoft

Supply chain security and Docker signing for production pipelines

Anchor image signing and SBOM in your pipeline?

We set up Cosign signing, whether key based or keyless, and automated SBOM generation with Syft in your CI pipeline, and use a policy controller to technically block unsigned images from production.

Cosign setup

Keyless signing with OIDC or classic key management with KMS integration

SBOM automation

Syft integration into the pipeline, SPDX or CycloneDX depending on requirements

Policy enforcement

Admission controller in Kubernetes that rejects unsigned images

10. Summary

Image signing and SBOM basics complement each other as two sides of the same supply chain security coin: signing proves origin and integrity of an image through its immutable digest, while an SBOM transparently lists every component it contains. Cosign from the Sigstore ecosystem enables both classic key based signing and keyless signing through OIDC identity and the public Rekor transparency log, entirely without your own public key infrastructure.

Syft generates a complete SBOM in SPDX or CycloneDX from a finished image, which can be anchored directly to the image digest as a signed attestation. Only a policy controller in Kubernetes turns the mere possibility of verification into an actually enforced control that excludes unsigned or unknown images from production deployment.

Image Signing and SBOM with Cosign and Syft — Key Takeaways

Digest instead of tag

Signatures always bind to the immutable SHA256 digest, never to a mutable tag.

Keyless signing

Short lived Fulcio certificates via OIDC replace long lived private keys and are logged in the Rekor log.

Syft SBOM

Analyzes image layers directly and produces a complete package list in SPDX or CycloneDX.

Policy controller

Enforces verification as an admission webhook in Kubernetes, blocking unsigned images at pod start.

11. FAQ: Image Signing and SBOM with Cosign and Syft

1What is image signing?
A signature proving origin and integrity of an image since the build.
2What is an SBOM?
A complete list of all packages, libraries and versions contained in the image.
3What is keyless signing?
Signing without a private key, via short lived Fulcio certificates based on OIDC identity.
4Why digest instead of tag?
Tags are mutable. The digest is immutable and unambiguously binds the signature to the content.
5What does Syft do?
Analyzes image layers and generates a complete SBOM with detected packages from many ecosystems.
6SPDX or CycloneDX?
SPDX for compliance, CycloneDX for security correlation. Syft supports both formats.
7What is an attestation?
A signed piece of extra information such as an SBOM, linked directly to the image digest.
8How is signing enforced?
Through a policy controller as an admission webhook, blocking pod starts without a valid signature.
9Do I need my own CA?
No, Fulcio handles it publicly. Only air gapped environments need a private Sigstore instance.
10Usable independently?
Yes, but the full benefit only emerges with the SBOM as a signed attestation on the image digest.