Signing Container Images With Cosign for the CRA
The Cyber Resilience Act does not contain the word "signature". It does not require Cosign, Sigstore or any particular tool. What it requires, from 11 December 2027, are outcomes that are hard to demonstrate without signing:
- Integrity. Products must "protect the integrity of stored, transmitted or otherwise processed data, personal or other, commands, programs and configuration against any manipulation or modification not authorised by the user" (Annex I, Part I, point (2)(f)).
- Secure distribution of updates. Manufacturers must "provide for mechanisms to securely distribute updates" (Annex I, Part II, point (7)).
- Due diligence on components. Manufacturers must exercise due diligence when integrating third-party components, open source included (Article 13(5)). Recital 34 lists checks such as update history and known vulnerabilities; it does not mention signatures, but a signature is how you know the component you checked is the component you ship.
For software delivered as container images, Cosign is the most widely used way to sign and verify. This post uses the commands of Cosign v3.1 (August 2026). Check cosign version; several flags changed between v2 and v3.
Sign by Digest, Never by Tag
A tag such as :1.4 or :latest can be moved to a different image; a digest (@sha256:...) cannot. Sign the digest, deploy by digest, and record the digest in the SBOM and the release notes. Cosign's signing examples all take an <IMAGE DIGEST>.
Option 1: Your Own Key
# once: create a key pair (or reference a KMS key instead of a file)
cosign generate-key-pair
# per release: sign the image by digest
cosign sign --key cosign.key registry.example.eu/app@sha256:4f1c...
# anyone with the public key: verify
cosign verify --key cosign.pub registry.example.eu/app@sha256:4f1c...
In production the private key should not be a file on a build machine. Cosign accepts key URIs for cloud KMSs and HashiCorp Vault (for example --key hashivault://release-signing), so the key never leaves the key store. Publish the public key where customers can find it, and document how you rotate it.
Option 2: Keyless
cosign sign registry.example.eu/app@sha256:4f1c...
Keyless signing authenticates the signer through an OIDC provider (the public Sigstore instance supports Google, GitHub and Microsoft identities, and CI systems such as GitHub Actions), obtains a short-lived certificate from Fulcio, and records the signature in the Rekor transparency log. There is no long-lived key to lose. There is an identity instead, and verification has to check it (see below).
What Goes Into the Public Log
By default Cosign records signatures in the public-good Rekor instance run by the Sigstore project. That entry is public and permanent. For a keyless signature it includes the signer's identity from the certificate, such as an e-mail address or a CI workflow path; for any signature it includes the artifact digest.
For open-source releases that transparency is the point. For a commercial product, decide deliberately:
- Public log. Anyone can audit that your signatures exist and when they were made; your identities and digests are public.
- No transparency log. In Cosign v3 the preferred way is a signing config without Rekor services (
cosign signing-config create, thencosign sign --signing-config ...); the older--tlog-upload=falseflag is deprecated but still accepted. Verifiers then need--insecure-ignore-tlog, and, as Cosign's own help text puts it, such artifacts "cannot be publicly verified". - Your own Sigstore. Run Fulcio, Rekor and a timestamp authority yourself, for example in an EU region, and give verifiers a trusted root (
cosign trusted-root create,--trusted-root). Transparency without publishing to a third party, at the cost of operating it.
Attach the SBOM as an Attestation
A signature says "this digest came from us". An attestation says something signed about that digest. Attaching the SBOM this way binds it to the exact image, which is what a customer's questionnaire and the CRA's component inventory (Annex I, Part II, point (1)) both need.
# attach a CycloneDX SBOM to the image, signed with the same key
cosign attest --key cosign.key --type cyclonedx \
--predicate sbom.cdx.json registry.example.eu/app@sha256:4f1c...
# verify it; the output is the signed statement containing the SBOM
cosign verify-attestation --key cosign.pub --type cyclonedx \
registry.example.eu/app@sha256:4f1c...
The same mechanism carries other statements: --type accepts spdxjson, openvex for exploitability statements, and slsaprovenance1 for build provenance. What the CRA itself requires of the SBOM is in the clause-by-clause SBOM post.
The Verification Mistake
A signature is only as good as the question the verifier asks. For keyless signatures, Cosign requires you to state which identity and which issuer you expect (--certificate-identity or --certificate-identity-regexp, and --certificate-oidc-issuer). It is tempting to satisfy it with a pattern that matches anything:
# proves that someone with a Sigstore identity signed this; not who
cosign verify --certificate-identity-regexp '.*' \
--certificate-oidc-issuer-regexp '.*' ghcr.io/example/app@sha256:...
Anyone with a GitHub account can produce a signature that passes that check. Pin the identity you actually expect, for example the release workflow of the upstream project:
cosign verify \
--certificate-identity-regexp '^https://github.com/example/app/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/example/app@sha256:...
The same applies to upstream images you pull into your own product. Verifying the publisher's signature at intake, against the publisher's identity, is due diligence you can show. Verifying against .* is not.
Where This Leaves You Under the CRA
- Signing your releases supports the integrity and secure-update requirements, but it is evidence of a process, not compliance by itself; the risk assessment decides what else is needed.
- Verifying upstream signatures against pinned identities is a concrete, recordable part of Article 13(5) due diligence.
- Attesting SBOMs, VEX and provenance to the digest turns per-release evidence into something a customer or a market surveillance authority can check without trusting your word.
Sources
- Regulation (EU) 2024/2847, Annex I, Article 13(5), recital 34, verbatim Official Journal text on this site.
- Cosign v3.1.3 command reference: sign, verify, attest, verify-attestation, signing-config create.
- Sigstore, Signing containers.
Commands reflect Cosign v3.1.3; check the reference for your version. This article is our reading of the Regulation and is not legal advice.