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.
Table of Contents
- 1. Why image signing and SBOM belong together
- 2. Cosign: fundamentals of image signing
- 3. Keyless signing with Sigstore and OIDC
- 4. Syft: generating an SBOM from an image
- 5. SBOM formats: SPDX and CycloneDX compared
- 6. Attestations: SBOM as a signed attachment on the image
- 7. Enforcing verification: policy controllers in Kubernetes
- 8. CI pipeline: build, sign, attach SBOM
- 9. Signing methods and SBOM formats compared
- 10. Summary
- 11. FAQ
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.