Practical DevSecOps with Sigstore and cosign

Candado metálico sobre teclado representando firma digital y seguridad en el pipeline

Sigstore and its CLI cosign have been transitioning from experiment to infrastructure for two years. Today large projects — Kubernetes, Istio, NPM with provenance, Python via PEP 740 — sign artifacts through the Sigstore chain. But between “it exists” and “my team uses it well” there’s still a gap. This article is about closing that gap: signing images and binaries in a way that the signature means something and doesn’t become another checkbox.

What Sigstore Actually Does

Sigstore is three pieces that fit together:

  • cosign: the CLI that signs and verifies artifacts (OCI images, blobs, SBOMs).
  • Fulcio: a certificate authority issuing short-lived certs (~10 minutes) bound to an OIDC identity — your GitHub, Google, or corporate identity provider.
  • Rekor: an immutable transparency log where signatures are recorded with audited timestamps.

The practical magic: you don’t manage persistent private keys. You sign with an identity (OIDC), get an ephemeral cert, sign, the cert expires, and the Rekor entry remains for anyone to verify later.

This keyless model eliminates the biggest source of signing incidents: compromised or lost keys. In return, it introduces dependency on Sigstore’s public infrastructure — or the need to deploy your own instance if you have strict requirements.

Signing an OCI Image

The most common use case: signing a Docker/OCI image after building.

# Build + push as usual
docker build -t registry.example.com/myapp:1.2.3 .
docker push registry.example.com/myapp:1.2.3

# Keyless sign with cosign (uses OIDC automatically)
cosign sign registry.example.com/myapp:1.2.3

Cosign detects the environment (GitHub Actions, Gitea Actions, GitLab CI, local) and gets the appropriate OIDC token. The signature attaches to the registry as an additional artifact (referenced manifest), not a separate tag.

Verify:

cosign verify registry.example.com/myapp:1.2.3 \
  --certificate-identity=ci@example.com \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com

Verification is not “does it have a signature?”. It’s “does it have a signature from the identity I expect?”. Without the identity part, a signature is decoration.

Integrating into a Real Pipeline

Three patterns that work for high-volume teams:

  • Auto-sign in CI: every successful build signs. The workflow has OIDC permission to Sigstore’s issuer. If the build passes, signing is free.
  • Policy in admission controller: Kyverno or Gatekeeper in Kubernetes reject pods whose image isn’t signed by authorized identities.
  • Verification in GitOps: Flux and Argo CD can verify signatures before reconciling. Signatures become real gatekeepers.

The common error is signing without verifying at deployment. Signing without verification is work without benefit.

Signing SBOMs and Provenance

Beyond images, Sigstore signs:

  • SBOMs (Software Bill of Materials) generated with Syft.
  • SLSA provenance generated by the builder — proof of how the image was built, which commit, which workflow, which tools.
  • Raw binaries with cosign sign-blob.

To meet SLSA Level 3 you need non-forgeable signed provenance. Sigstore is the natural mechanism to get it without standing up your own infrastructure.

Keys vs. Keyless: When to Use Which

You won’t always want OIDC keyless:

  • Keyless: default, less operational overhead, less key-compromise risk, dependency on public Sigstore.
  • Keypair: persistent key (RSA or ECDSA), fully offline, you manage custody. Useful for air-gapped or strict requirements.
  • KMS: key in HashiCorp Vault, AWS KMS, GCP KMS, etc. Good balance of central management and verifiable signing.

For most cloud-native teams, keyless is sufficient and operationally simpler. For regulated environments, KMS is usually the path.

Private Sigstore: When It Makes Sense

Public Sigstore has limits: shared usage, dependency on foreign infrastructure, OIDC identities exposed in public Rekor. For some cases, deploying scaffolding — your own Fulcio + Rekor instance — makes sense.

Typical cases:

  • Regulated where signature metadata is sensitive.
  • Air-gapped or networks with no public Sigstore access.
  • High volume justifying operational costs.

For everyone else, public is more than enough and much less work.

Common Mistakes

I’ve seen teams break signature-based DevSecOps in these ways:

  • Sign everything, verify nothing. Signing without verification is theatre.
  • Accept any identity. Verifying “has signature” without validating who signed is nearly equivalent to not signing.
  • Forget to rotate. In keypair mode, if you don’t rotate annually, you lose the benefit.
  • Not storing Rekor log entries. For long-term audit, you need the Rekor entry UUID as evidence.
  • No runbook when it fails. If public Sigstore has an incident, your CI halts. Have plan B.

Minimal Checklist

A team starting with Sigstore without complications:

  • Sign in CI (keyless) for main images.
  • Verify at deployment (Kyverno, Flux, Argo).
  • List of authorized identities versioned in Git.
  • Alert when an unsigned image reaches production.
  • Quarterly review of what’s signed and what isn’t.

With that, you’re already ahead of average.

Conclusion

Sigstore moved from experimental project to de-facto software-signing infrastructure. Adoption friction has dropped. What remains is integrating it so it means something — really verifying, with well-defined identities, and clear runbooks when it fails. Signing for signing’s sake is worse than not signing: it gives the illusion of security without the benefits. Well applied, it closes one of the doors supply-chain attackers have exploited for years.

Follow us on jacar.es for more on DevSecOps, supply chain, and less-vulnerable deployments.

Entradas relacionadas