How to verify a Rasid image
Published · Fahad
Pulling an image you have not verified is pulling a binary you cannot defend in an audit. Every Rasid image carries enough provenance evidence to prove what it is, who built it, and that the chain has not been tampered with. This is the practical guide to walking through that evidence end-to-end.
What you will verify
For each Rasid image you pull, four pieces of evidence are available:
- A Cosign signature — the image was signed by a Rasid signing identity issued by our self-hosted Sigstore Fulcio.
- A Rekor transparency-log entry — the signature was publicly logged at the time it was created.
- An SBOM — the image’s exact package list, in CycloneDX 1.5 and SPDX 2.3 formats.
- An in-toto SLSA Level 3 attestation — the build provenance binding image → build environment → recipe.
You should walk through all four before promoting an image to production. The whole pipeline takes a few seconds in CI.
Prerequisites
- Cosign — the Sigstore CLI (Apache 2.0). Install with your package manager or grab a release binary from sigstore.dev.
- Optional:
cyclonedx-cliorsyftfor SBOM inspection. - Optional:
slsa-verifierfor richer SLSA attestation parsing.
All four tools are open-source and produce identical results on identical inputs. Nothing in the verification path requires a Rasid-issued account or API token.
Step 1 — Pull the image
docker pull images.rasid.cc/postgres:17
The registry at images.rasid.cc follows the OCI Distribution v2 spec. Anonymous pulls are open. The catalogue list at images.rasid.cc/v2/_catalog works in any browser.
Step 2 — Verify the signature
cosign verify images.rasid.cc/postgres:17 \
--key https://rasid.cc/.well-known/rasid-cosign.pub
What this checks:
- The image bytes you pulled match a digest that Rasid signed.
- The signature was made with the private half of the key whose public half is published at
rasid.cc/.well-known/rasid-cosign.pub. - An entry recording the signature exists on the Rekor transparency log at
rekor.rasid.cc.
If the command exits 0, you have all three. If it exits non-zero with no matching signatures or cosign.sig not found, the image is unsigned or the signature does not match — do not run it, and report it to [email protected].
If you want to belt-and-braces verify against a specific Fulcio root:
cosign verify images.rasid.cc/postgres:17 \
--key https://rasid.cc/.well-known/rasid-cosign.pub \
--certificate-chain https://rasid.cc/.well-known/rasid-fulcio-chain.pem
Step 3 — Pull and inspect the SBOM
The SBOM is published as an OCI artifact next to the image. The easiest way to fetch it:
cosign download sbom images.rasid.cc/postgres:17 > postgres-17.sbom.json
Or via direct HTTPS:
curl -fsSL -o postgres-17.cdx.json \
https://images.rasid.cc/postgres/sbom-17.cdx.json
Pipe it into your existing vulnerability scanner — Grype, Trivy, OWASP Dependency-Track, GitLab Dependency Scanning — and you get the same coverage as if it had scanned the live image, without pulling the image bytes again.
To diff SBOMs across releases (useful when you want to see exactly what changed between yesterday’s daily rebuild and today’s):
cyclonedx-cli diff --output-format text \
postgres-17-yesterday.cdx.json postgres-17-today.cdx.json
Step 4 — Validate the SLSA attestation
cosign verify-attestation images.rasid.cc/postgres:17 \
--type slsaprovenance \
--key https://rasid.cc/.well-known/rasid-cosign.pub
This proves not just that we signed the image, but that we have published a SLSA Level 3 build provenance statement describing what built it: the recipe, the build runner, the source commit, the timestamp. The attestation is in-toto v1.0 with SLSA provenance v1.0.
If you want a structured view of the attestation:
cosign verify-attestation images.rasid.cc/postgres:17 \
--type slsaprovenance \
--key https://rasid.cc/.well-known/rasid-cosign.pub \
| jq '.payload | @base64d | fromjson | .predicate'
What “verified” means and does not mean
A successful pass of all four steps tells you:
- The image bytes are the bytes Rasid signed.
- The signature is publicly logged so it cannot be silently swapped.
- The package list is the published SBOM.
- The build provenance was attested at build time.
It does not tell you:
- That a CVE-free image will stay CVE-free forever — pin a digest, subscribe to advisories.
- That the image is appropriate for your workload — that is your engineering decision.
- That your runtime configuration is safe — image-level hardening does not replace runtime hardening.
Verification is necessary, not sufficient. But running production on unverified images is operating blind.
Wiring this into CI
The minimal CI verification step, in any runner:
#!/usr/bin/env sh
set -eu
IMAGE="images.rasid.cc/postgres:17"
cosign verify "$IMAGE" --key https://rasid.cc/.well-known/rasid-cosign.pub
cosign verify-attestation "$IMAGE" --type slsaprovenance \
--key https://rasid.cc/.well-known/rasid-cosign.pub
Forgejo Actions example:
- name: Verify Rasid base image
run: |
curl -fsSL -o /usr/local/bin/cosign "$COSIGN_URL/cosign-linux-amd64"
chmod +x /usr/local/bin/cosign
cosign verify images.rasid.cc/postgres:17 \
--key https://rasid.cc/.well-known/rasid-cosign.pub
Same pattern works for Jenkins, Buildkite, GitLab CI, Drone, CircleCI — any runner that gives you a shell.
What to do if verification fails
If cosign verify fails on an image you pulled fresh from images.rasid.cc:
- Pull again to rule out a corrupted local layer cache.
- Check the SHA-256 of the local image manifest against
images.rasid.cc/v2/<image>/manifests/<tag>. - Email
[email protected]with the image tag, your timestamp, and your geographic region. We treat verify-failure reports as a P0 incident.
— Fahad