
September 10, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Your deployment pipeline builds a release artifact every week. A compromised registry mirror or a leaked CI token could swap that binary before anyone notices. Learning to sign and verify artifacts with Sigstore cosign gives you cryptographic proof of origin without running your own PKI. Sigstore handles short-lived certificates through Fulcio, records signatures in Rekor, and lets cosign attach those signatures to OCI images, plain files, and SBOMs. This guide walks through install, signing modes, verification, and the CI patterns I use on production Linux deployment pipelines.
cosign sign (keyless OIDC or a static key), then verify with cosign verify using the publisher identity or public key before deploy.What is Sigstore cosign and why should you sign artifacts?
Cosign is the CLI from the Sigstore project for signing and verifying software artifacts. It supports container images, Helm charts, generic blobs, and signed attestations such as SBOMs and SLSA provenance.
Traditional GPG signing works, but key management is painful at team scale. Cosign offers two practical paths: keyless signing through OpenID Connect, or long-lived encrypted key pairs you store in your secrets manager. Both produce signatures verifiable by anyone with cosign installed.
On client projects where I maintain GitLab CI plus Deployer releases, artifact trust is not optional. A signed container image or release tarball lets the deploy step reject anything that did not come from your pipeline. That single check closes a common supply-chain gap between build and production.
The three Sigstore components matter when you debug verification failures. Fulcio issues X.509 certificates bound to your CI identity. Rekor stores a tamper-evident log entry for each signature. Cosign attaches the signature to the artifact itself or stores it as OCI referrers metadata alongside container images.
If you already sign Git commits with GPG or SSH, cosign covers the next layer: the built output. Read the companion piece on signing commits for supply chain trust for a full chain from source to deploy.
Which artifact types cosign supports
- OCI container images — Docker, GHCR, GitLab Container Registry, ECR, and any OCI-compliant registry
- Generic blobs — tarballs, ZIP archives, PHP phar files, compiled binaries
- Helm charts — packaged charts pushed as OCI artifacts
- Attestations — in-toto statements for SBOMs, vulnerability scans, and SLSA provenance
How do you install cosign and choose a signing mode?
Install cosign on your workstation and CI runners before you touch production registries. The binary is a single static executable with no runtime dependencies.
Install cosign on Linux
# Download latest release (check https://github.com/sigstore/cosign/releases)
COSIGN_VERSION=v2.4.1
curl -LO "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64"
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
cosign version Verify the binary checksum against the release page before you install it on production servers. I treat cosign like any other supply-chain tool: download once, checksum, then promote the same binary to all runners.
Keyless signing vs static keys
Keyless signing uses your CI platform OIDC token. Cosign exchanges that token with Fulcio for a certificate valid about ten minutes. The private key never leaves memory. Rekor records the signature publicly.
Static key signing generates a long-lived key pair. You encrypt the private key with a passphrase and store it in GitLab CI variables, GitHub Actions secrets, or Ansible Vault. Verification uses the exported public key or a pinned key in your policy file.
| Criteria | Keyless (OIDC) | Static encrypted key |
|---|---|---|
| Key rotation | Automatic per job | Manual rotation schedule |
| Identity binding | CI workflow + repo URL | Whoever holds the key file |
| Offline verify | Needs Rekor lookup | Public key only |
| Best for | Cloud CI with OIDC | Air-gapped or legacy runners |
| Audit trail | Rekor transparency log | Your own logging |
For GitLab CI pipelines on shared EC2 infrastructure — the same pattern I use on sister legal-tech sites — keyless signing through id_tokens is the default choice in 2026. Static keys remain useful when OIDC is unavailable or when you sign artifacts outside CI.
Generate a static key pair
cosign generate-key-pair
# Creates cosign.key (private) and cosign.pub (public)
# Store cosign.key encrypted; commit cosign.pub or publish it Never commit the private key. Export the public key to your repository root or a .well-known path so downstream teams can verify without asking you for files.
How do you sign container images, binaries, and blobs with cosign?
Signing is one command per artifact type. The syntax differs slightly between OCI images and flat files, but the verification model stays consistent.
Sign a container image (keyless via GitHub Actions)
permissions:
id-token: write
contents: read
packages: write
steps:
- uses: sigstore/cosign-installer@v3
- run: docker build -t ghcr.io/org/app:${{ github.sha }} .
- run: docker push ghcr.io/org/app:${{ github.sha }}
- run: |
cosign sign --yes ghcr.io/org/app:${{ github.sha }} The --yes flag skips the interactive prompt in CI. Fulcio binds the certificate to your GitHub workflow identity. Rekor stores the entry automatically.
Sign a container image (static key)
export COSIGN_PASSWORD="your-passphrase"
cosign sign --key cosign.key registry.example.com/myapp:1.4.2 Pass the passphrase through an environment variable, not a CLI flag. Shell history and process listings leak flags; environment injection from CI secret stores does not.
Sign a generic blob or release tarball
cosign sign-blob --key cosign.key \
--output-signature app.tar.gz.sig \
--output-certificate app.tar.gz.pem \
app.tar.gz Distribute three files together: the artifact, the .sig file, and the certificate. Verification uses cosign verify-blob with the same trio. This pattern works well for Laravel release archives built on CI and deployed via Deployer symlink swaps.
Attach an SBOM attestation
cosign attach sbom --sbom sbom.spdx.json \
registry.example.com/myapp:1.4.2
cosign sign --key cosign.key \
--attachment sbom \
registry.example.com/myapp:1.4.2 SBOM attestations let security teams trace dependencies without rebuilding the image. Pair this with your existing artifact repository strategy so signed images and SBOMs live in one trusted registry.
- Build and tag the artifact with an immutable digest or version tag.
- Sign immediately after the build step — never sign a artifact that passed through manual upload.
- Push the artifact and signature to the registry in the same pipeline job.
- Record the digest in your deployment manifest or GitOps repo.
- Verify at deploy time against the pinned digest plus signature.
How do you verify signed artifacts in CI/CD pipelines?
Signing without verification is theatre. Every deploy job, Kubernetes admission hook, and manual pull script should call cosign verify and exit non-zero on failure.
Verify a keyless-signed image
cosign verify \
--certificate-identity-regexp="https://github.com/myorg/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
ghcr.io/myorg/app@sha256:abc123... Pin the digest, not a floating tag. Tags are mutable; digests are not. A common mistake is verifying :latest while the registry silently retagged it overnight.
Verify with a static public key
cosign verify --key cosign.pub registry.example.com/myapp:1.4.2 Commit cosign.pub to your infrastructure repo. Rotation means generating a new key pair, re-signing all active artifacts, and updating the pinned public key in one coordinated change.
Verify a signed blob before install
cosign verify-blob \
--key cosign.pub \
--signature app.tar.gz.sig \
app.tar.gz On air-gapped servers, copy the public key out of band once. Verification then runs fully offline with no Rekor dependency.
GitLab CI example with OIDC
sign-image:
image: gcr.io/projectsigstore/cosign:v2.4.1
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- cosign sign --yes "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" GitLab documents the id_tokens block in their CI/CD reference. Set aud: sigstore exactly — a wrong audience makes Fulcio reject the token with an opaque error.
Policy enforcement with CUE or Rego
Large teams move verification rules into policy files. Cosign supports cosign verify --policy policy.cue to enforce allowed identities, certificate extensions, and annotation requirements in one place. Start with shell-level verify flags; adopt policy files when you manage more than five images.
Wire verification into the same pipeline stage that runs testing and optimization checks. A failed signature should block deploy exactly like a failed PHPUnit suite.
What are common cosign mistakes and how do you avoid them?
Most cosign failures I see in production are configuration issues, not crypto bugs. The fixes are usually one flag or one missing CI permission.
Gotcha: missing OIDC permissions
GitHub Actions needs id-token: write. GitLab needs an explicit id_tokens entry. Without OIDC, keyless signing fails silently or prompts for a key file that does not exist on the runner.
Gotcha: verifying tags instead of digests
Always verify image@sha256:…. An attacker with registry write access can move a tag to an unsigned image. Digest pinning closes that hole.
Gotcha: clock skew on runners
Fulcio certificates expire quickly. A VM with drifted system time gets "certificate expired" errors. Run NTP on all CI runners — the same baseline I apply during server maintenance work.
Store registry credentials in your secrets manager, not in the Dockerfile. Cosign signatures prove who built the artifact; registry ACLs prove who can push. You need both layers.
For Kubernetes clusters, install the Sigstore Policy Controller or write a validating admission webhook that calls cosign verify on every pod spec image reference. That catches unsigned images even when a developer bypasses the deploy script locally.
On a legal-tech portal deployment, I treat cosign the same way I treat SSL certificates: renewals and rotations go on a calendar, and verification runs automatically. Manual trust decisions do not scale when you maintain multiple sister sites on one shared pipeline.
Related reading: signing container images with cosign for OCI-specific flags, and adding automated checks to CI for pipeline structure patterns.
Key Takeaways
- Install cosign on CI runners and verify checksums before promoting the binary to production infrastructure.
- Prefer keyless OIDC signing when your platform supports it; use encrypted static keys for air-gapped or legacy runners.
- Sign immediately after build in the same job — never sign artifacts that passed through manual upload channels.
- Verify with pinned sha256 digests and fail closed; floating tags defeat the purpose of signature checks.
- Attach SBOM attestations alongside signatures so security teams can audit dependencies without rebuilding.
- Combine cosign with commit signing, registry ACLs, and admission policy for defence in depth across the supply chain.
People Also Ask
Is cosign free to use in production?
Yes. Cosign and the public Sigstore infrastructure (Fulcio, Rekor) are open source and free for standard use. Large enterprises can also run private Sigstore instances if public transparency logs are not acceptable for compliance reasons.
Can cosign sign artifacts other than Docker images?
Yes. The cosign sign-blob and cosign verify-blob commands handle any file — tarballs, binaries, configuration bundles, and firmware images. Signatures are stored as separate .sig files or embedded in an OCI artifact wrapper.
Do I still need GPG if I use cosign?
They solve different problems. GPG or SSH commit signing proves who authored source code. Cosign proves who built and published the release artifact. Use both for a complete chain from commit to deploy.
How do I rotate cosign signing keys?
For static keys, generate a new pair, update CI secrets, re-sign active release artifacts, publish the new public key, and retire the old key after all deployed versions are replaced. Keyless signing rotates automatically because each CI job receives a fresh short-lived certificate.
Build a verifiable supply chain on your next project
You now have the commands to sign and verify artifacts with Sigstore cosign across images, blobs, and attestations. Start with one pipeline job: sign on merge to main, verify before deploy. Expand to SBOM attachments and Kubernetes admission policy once the basics are stable.
If you want help wiring cosign into GitLab CI, Deployer releases, or a private registry on Ubuntu, I can audit your current pipeline and add verification gates that fail closed. See the Notary Kathmandu deployment pipeline for an example of multi-site CI/CD work, or explore custom software development services for full-stack delivery including infrastructure hardening.
For quick JSON policy checks while you draft CUE verification rules, use the free JSON formatter tool. When you are ready to talk through your stack, contact us with your registry URL and CI platform — we can map a cosign rollout in one working session.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

