Verifying a release¶
Every Barbacana release ships three artifacts in ghcr.io, all bound to the same image digest:
- A multi-arch image at
ghcr.io/barbacana-waf/barbacana:vX.Y.Z(and:latest). - A cosign keyless signature over the image digest.
- A CycloneDX SBOM attested to the same digest, stored as an OCI 1.1 referrer alongside the image.
Canonical registry
ghcr.io/barbacana-waf/barbacana is the canonical signed registry. A convenience mirror at docker.io/barbacana/barbacana carries identical image bits (same digest) but does not carry the cosign signature or SBOM attestation. For deployments that verify signatures, pull from ghcr.io.
Edge builds at ghcr.io/barbacana-waf/barbacana-edge are not signed and not attested. Do not run them in production; do not apply the procedures below to them — they will fail.
Prerequisites¶
| Tool | Used for | Install |
|---|---|---|
| cosign ≥ 3.0 | Signature + attestation verification, SBOM download | Installation |
| jq | SBOM extraction | Download |
| trivy ≥ 0.50 | CVE scanning | Installation |
| grype (optional) | Alternative CVE scanner | Installation |
1. Verify the image signature¶
The signature proves the image at the given reference was produced by the Barbacana release workflow on a tagged commit. It does not say anything about what is inside the image — that is what the SBOM attestation in step 2 is for.
cosign verify \
--certificate-identity=https://github.com/barbacana-waf/barbacana/.github/workflows/release.yml@refs/heads/master \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/barbacana-waf/barbacana:vX.Y.Z
Example run against latest:
Verification for ghcr.io/barbacana-waf/barbacana:latest --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority certificates
[{"critical":{"identity":{"docker-reference":"ghcr.io/barbacana-waf/barbacana:latest"},
"image":{"docker-manifest-digest":"sha256:3d900fe257775b62a4179716f972991675a26faf23a1eeb10bef52410e4943f2"},
"type":"https://cyclonedx.org/bom"},"optional":{}},
{"critical":{"identity":{"docker-reference":"ghcr.io/barbacana-waf/barbacana:latest"},
"image":{"docker-manifest-digest":"sha256:3d900fe257775b62a4179716f972991675a26faf23a1eeb10bef52410e4943f2"},
"type":"https://sigstore.dev/cosign/sign/v1"},"optional":{}}]
The certificate identity pins the signature to release.yml in the barbacana-waf/barbacana repository, run via workflow_dispatch on master (the release workflow creates the version tag at the end of its own run, so the OIDC subject embeds @refs/heads/master, not the eventual tag). The OIDC issuer pins it to GitHub Actions' token endpoint. Together they prevent a signature produced by any other repo, workflow, or trigger from passing.
A successful run prints a JSON array of verified signed items and exits 0. With cosign v3 defaults, the array has two entries at the same digest: the image signature (type: https://sigstore.dev/cosign/sign/v1) and the CycloneDX SBOM attestation (type: https://cyclonedx.org/bom). Both are checked against the same certificate identity, so a tampered or missing attestation will fail this step too — you don't need to wait for step 2 to catch it.
A failure means one of the following:
- The image at that reference is unsigned, or signed by an identity that does not match (i.e. not produced by this repo's release workflow).
- The transparency log entry for the signature has been tampered with or removed.
- The image reference points to a different digest than the one that was signed (e.g. a tag was force-pushed).
In all three cases, treat the image as untrusted.
2. Verify the SBOM attestation¶
The attestation is a cosign-signed in-toto statement carrying a CycloneDX SBOM as its predicate. Verifying it proves the SBOM came from the same release workflow that signed the image and is bound to that image's digest.
cosign verify-attestation \
--type cyclonedx \
--certificate-identity=https://github.com/barbacana-waf/barbacana/.github/workflows/release.yml@refs/heads/master \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/barbacana-waf/barbacana:vX.Y.Z
Example run against latest:
Verification for ghcr.io/barbacana-waf/barbacana:latest --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority certificates
{"payload":"eyJfdHlwZSI6Imh0dHBz[...]","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"..."}]}
A success prints the verified in-toto envelope to stdout and exits 0. Pipe it through jq to inspect the predicate type and the bound subject:
cosign verify-attestation --type cyclonedx \
--certificate-identity=https://github.com/barbacana-waf/barbacana/.github/workflows/release.yml@refs/heads/master \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/barbacana-waf/barbacana:vX.Y.Z 2>/dev/null \
| jq -r '.payload' | base64 -d | jq '.predicateType,.subject'
Example run against latest:
[
{
"name": "ghcr.io/barbacana-waf/barbacana",
"digest": {
"sha256": "3d900fe257775b62a4179716f972991675a26faf23a1eeb10bef52410e4943f2"
}
}
]
Failure modes:
none of the attestations matched the predicate type: cyclonedx— the image has no CycloneDX SBOM attached. Either the reference is wrong, the image was not produced by a release tag, or the attestation has been stripped from the registry.- The certificate-identity check fails — same meaning as in step 1: the SBOM was attested by something other than the release workflow.
Both verification steps should pass before trusting the SBOM in step 4.
3. Enforce verification at admission (Kubernetes)¶
Steps 1 and 2 can be enforced automatically by a Kubernetes admission controller, so unsigned or unattested images are rejected at deploy time without any manual step. Two common options:
- Sigstore Policy Controller — purpose-built admission webhook from the Sigstore project. Configure a
ClusterImagePolicywith the same certificate identity and OIDC issuer used in steps 1–2. - Kyverno — general-purpose policy engine with a built-in
verifyImagesrule that calls cosign internally.
Either lets the cluster reject any pod whose image fails the same checks performed manually above.
4. Retrieve the SBOM¶
For tooling that consumes the SBOM file directly (Dependency-Track, GUAC, custom scanners), download and extract the CycloneDX predicate:
cosign download attestation \
--predicate-type https://cyclonedx.org/bom \
ghcr.io/barbacana-waf/barbacana:vX.Y.Z \
| jq -r '.dsseEnvelope.payload' | base64 -d | jq '.predicate' \
> barbacana.cdx.json
Example run against latest (download, then inspect the resulting file):
1.6
183
What each stage does:
cosign download attestationfetches the signed in-toto bundle for the CycloneDX predicate type from the registry. No network call to Rekor is made — this is a registry read.jq -r '.dsseEnvelope.payload'extracts the base64-encoded DSSE payload (the in-toto statement).base64 -d | jq '.predicate'decodes the statement and unwraps the CycloneDX document.
The result is a standalone CycloneDX 1.x JSON document at barbacana.cdx.json.
cosign download attestation does not verify the signature — it only fetches. Always run step 2 first; only trust an SBOM whose attestation has already been verified.
5. Scan for CVEs¶
Two equivalent paths.
Direct (no manual download) — trivy fetches the attestation from the registry itself:
Example run against latest:
┌──────────────────────────────────────────────────────┬──────────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├──────────────────────────────────────────────────────┼──────────┼─────────────────┤
│ ghcr.io/barbacana-waf/barbacana:latest (debian 13.4) │ debian │ 0 │
├──────────────────────────────────────────────────────┼──────────┼─────────────────┤
│ ko-app/barbacana │ gobinary │ 0 │
└──────────────────────────────────────────────────────┴──────────┴─────────────────┘
The vulnerability count will change over time
The 0 reported in the example outputs below is the result at the time the scan was captured. CVEs are disclosed against existing components continuously, so the same image will start reporting findings without anything in the image changing.
Best for operators who just want a vuln report against a deployed image. --sbom-sources oci tells trivy to prefer the registry-attached SBOM over re-deriving one from the image layers, which is faster and produces results that match exactly what was attested.
From a downloaded SBOM — useful for air-gapped scanning or when the same SBOM is fed into multiple tools:
Example run against the SBOM extracted from latest:
┌────────┬──────────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├────────┼──────────┼─────────────────┤
│ │ gobinary │ 0 │
└────────┴──────────┴─────────────────┘
Or with grype:
Both scanners auto-detect CycloneDX format. Severity, output format, and ignore-policy flags are scanner-specific — see the respective documentation.
A clean scan today does not mean the image is clean tomorrow; new CVEs are disclosed against existing components continuously. See the next section.
6. Verify the binaries (optional)¶
The container image is the recommended distribution form. For users who download the binary archives directly from a GitHub Release, each release attaches a cosign-signed checksums.txt.bundle and a SLSA3 provenance file (barbacana.intoto.jsonl).
Verify the checksums file (the SHA-256 entries inside cover every archive):
cosign verify-blob \
--certificate-identity=https://github.com/barbacana-waf/barbacana/.github/workflows/release.yml@refs/heads/master \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--bundle checksums.txt.bundle \
checksums.txt
Or verify a specific archive against its SLSA3 provenance with slsa-verifier:
slsa-verifier verify-artifact barbacana_X.Y.Z_linux_amd64.tar.gz \
--provenance-path barbacana.intoto.jsonl \
--source-uri github.com/barbacana-waf/barbacana
Reference¶
- Sigstore documentation — background on cosign, Fulcio, Rekor, and the in-toto attestation format.
- CycloneDX specification — the SBOM format used in the attestation.