skip to content

Why is a cosign verify step with no expected certificate identity or OIDC issuer worthless?

level: middleimportance: must knowfreq 62%

answer

  1. signature says who, not whether trustworthy
  2. anyone can obtain a certificate
  3. expected identity plus expected issuer
  4. same string, different provider, different principal
  5. anchor any identity regexp

basics

~20 s

A bare cosign verify proves only that somebody obtained a Sigstore certificate and signed the artifact, which anyone with an email or a CI account can do. Pin the expected identity and the issuer that asserted it.

solid answer

~50 s

Keyless signing is open by design: the certificate authority will issue a short-lived signing certificate to anyone who can authenticate to a supported OIDC provider. So "a valid Sigstore signature exists over this digest" is a statement about the world, not about your pipeline — it is satisfied by any stranger who signed the same artifact. The check you actually want is `--certificate-identity` (or `--certificate-identity-regexp`) plus `--certificate-oidc-issuer`, which say *this* identity, as asserted by *that* provider, signed it. You need both: an identity string is only meaningful relative to the issuer that vouched for it, since the same email at a different provider is a different principal, and the issuer alone would accept every user of that provider. Modern cosign refuses a keyless verify without them, which is why a release gate that still "passes" on a bare verify is usually running something old or using a key.

code

bash · 8 lines
bash
# proves only that SOMEBODY signed this file through the public chain
cosign verify-blob --bundle appliance.deb.bundle appliance.deb

# proves that this identity, as asserted by this issuer, signed it
cosign verify-blob --bundle appliance.deb.bundle \
  --certificate-identity=https://git.example.com/appliance/.ci/release.yml@refs/heads/main \
  --certificate-oidc-issuer=https://git.example.com \
  appliance.deb

go deeper

for a junior

Remember that a Sigstore certificate is issued to anyone who can log in to a supported provider, so a signature by itself says nothing about who your artifact came from.

for a middle

Explain what the identity and issuer flags each pin, and why an identity string is meaningless without the provider that asserted it.

for a senior

Be able to read a release gate and spot the failure fast: keyless without identity flags, an unanchored regexp, a tag instead of a digest, or a verify whose exit status is ignored.

for a principal

Own the distinction between verifying origin and judging fitness, and make sure nobody in the organisation treats a green verify step as evidence the artifact is safe to run.

## A signature answers "who", and only if you asked The keyless flow in Sigstore deliberately has no gatekeeper. You authenticate to an OIDC provider, the certificate authority issues a short-lived certificate binding your ephemeral public key to that identity, you sign, and the event is recorded in a transparency log. This is what makes the ecosystem usable — no key distribution, no enrolment ceremony — and it is also why the certificate itself confers no privilege. It attests an identity; it does not attest worthiness. So consider what a bare `cosign verify <artifact>` establishes. It establishes: this signature is cryptographically valid over this digest, and the certificate that made it chains to the Sigstore root. Every one of those facts is also true of a signature made by an anonymous person who pulled your artifact, signed it under their own identity, and published the result. Nothing in that verification distinguishes your release job from them. A release gate built on it accepts anything anyone ever signed through the public chain — the gate is decorative. ### The two flags that make it a real check - `--certificate-identity` pins the exact identity string in the certificate — for a CI job that is typically a workflow or workload identity URI; for a human, an email address. `--certificate-identity-regexp` allows a pattern where the identity legitimately varies. - `--certificate-oidc-issuer` pins the provider URL that asserted that identity. Both are required, and the reason is worth being able to state cleanly. An identity string has no global meaning. `[email protected]` at your corporate SSO and `[email protected]` at some public consumer provider are different principals that happen to render as the same text, and an attacker who can create an account somewhere with a chosen identity string can produce a certificate carrying it. Pinning the issuer without the identity is the mirror failure: you would accept every user of that provider, which for a large public provider is essentially the internet. ### The regexp trap `--certificate-identity-regexp` is where a correct-looking gate quietly reopens. An unanchored pattern matches a substring, so a pattern intended to match one repository's workflow can match an identity that merely *contains* that text, including one an attacker controls the tail or head of. Anchor the pattern and keep it as narrow as the real variation demands; a regexp is a concession to necessity, not the default. ### Key-based verification is a different shape If you sign with `--key`, the public key *is* the identity, and the identity and issuer flags do not apply — you verify against the key you trust. That is not a loophole so much as a different trust anchor with a different cost: you now own key generation, storage, rotation and revocation, which is precisely what keyless was designed to remove. ### What verification still does not tell you Even a correctly pinned verify answers exactly one question: the identity you expected vouched for these exact bytes. It does not say the artifact is free of known vulnerabilities, that it was built from reviewed source, or how it was produced. Candidates who slide from "signature verified" to "artifact is safe" have made the domain's most common category error. Origin, contents and production history are three separate claims, and a signature carries only the first. ### How this shows up in a review When you read someone's release gate, the diagnostic sequence is short. Is this keyless or key-based? If keyless, are both identity flags present? If a regexp is used, is it anchored and does it describe an identity only your build system can obtain? Is the artifact referenced by digest, so the thing verified is the thing deployed? Does the step fail the pipeline when verification fails, or is its exit status swallowed? Most broken gates fail at the first or the last of those.

  • Why is pinning the OIDC issuer alone not enough?
    Because it accepts every identity that provider will authenticate. For a large public provider that is effectively anyone who can register an account. The issuer scopes *which namespace* an identity string lives in; the identity says *which principal* inside it. Dropping either half turns the check into "someone somewhere signed this".
  • What is the risk of --certificate-identity-regexp?
    An unanchored or loose pattern matches identities you never meant to trust, including ones an attacker can obtain by naming a repository or workflow so the pattern matches it. Anchor the expression at both ends and keep the variable part as small as the real variation requires.
  • If you sign with your own key pair instead, do you still pass the identity flags?
    No. With `--key` the public key is the trust anchor and the certificate identity flags do not apply. You have traded an identity-pinning problem for a key-management one: generation, storage, rotation and revocation are now yours, which is exactly the burden keyless signing removes.
  • The gate verifies a tag, but the deployment resolves the same tag later. What can go wrong?
    The tag can be repointed between the two resolutions, so the bytes verified are not the bytes deployed. Verify by digest and deploy that same digest, passing it through the pipeline as a value rather than re-resolving a mutable name at each step.

It is a border check where the officer confirms the passport is genuine and unforged, then waves the traveller through without ever reading the name.

saying these in an interview costs you the question

  • Says a valid signature proves the artifact came from your pipeline
  • Treats the issuer flag as optional detail
  • Slides from signature verified to artifact is safe
  • Uses a loose unanchored identity regexp and calls it pinned
  • Believes the certificate authority only issues to approved publishers

context