Skip to content

Image signing and verification

Every container image pushed to your organization’s private registry by someone who is allowed to push is signed by Sencai with a key that belongs to your organization alone. The signature covers the image’s digest - the fingerprint of its exact content - so you can check, later and on any machine, that the image a server is running is the one your organization pushed and Sencai signed.

A signature on a digest says:

  • Sencai signed this exact content, and no other. A changed image has a different digest and no signature.
  • The push came from an account that was allowed to push to your registry at the time. Pushes from any other account are refused and never signed.
  • Who pushed it and when. The signed payload records your organization, the pusher (a member, or your CI credential), the time of the push and the fingerprint of the signing key.
  • For an image pushed by a job on a hosted runner, which run and which commit built it. These two fields are present only when the push was tied to exactly one job; they are absent from images pushed any other way.

It does not say the image is free of vulnerabilities (that is what the scan is for) or that the code inside is what you meant to build. It proves identity and integrity, not quality.

Each image also carries a signed scan attestation: the scan result, signed with the same key, so a result you hold can be checked as genuine and tied to one digest.

Your organization’s public key is a normal cosign public key file. It is named after your organization’s short name, for example sencai-acme-cosign.pub.

  1. Open Registry and select the Sencai tab.
  2. Open any image. The Signing keys card lists every key version with its algorithm, its SHA-256 fingerprint, when it was pinned and whether it is retired, with a Download button per version. The Prove what you deployed card has a Public key (sencai-acme-cosign.pub) button that downloads the key that signed the version you are looking at.

Keep the file under the name it is downloaded with: the commands the image page shows use that name. The key of an older version is downloaded as, for example, sencai-acme-cosign-v1.pub. Anyone who can read your organization’s registry can download the key, auditors included. Until the first image of yours has been signed there is no key, and the card says so.

Always fetch the key from the app while you are signed in, not from a copy you found elsewhere, and keep the fingerprint from the page next to the file so you can compare. A verification is only as trustworthy as the key it uses.

You need cosign: version 2.6 or later in the 2.x line, or version 3.x. Take the digest from the image page and verify by digest, never by tag - a tag can be moved, a digest cannot. The examples use acme as the organization and sencai-acme-cosign.pub as the key file:

Terminal window
cosign verify \
--key sencai-acme-cosign.pub \
--insecure-ignore-tlog=true \
--new-bundle-format=false \
git.sencai.space/acme/api@sha256:<digest>

A passing run prints the signed payload and ends with a line confirming the claims and the signature were verified. The Prove what you deployed card on the image page shows the exact command for the version you have selected, ready to copy. For a multi-platform image, select a platform in the Platforms table to get the command for that platform image. The key file in a command is the one for the key version that signed that image: an image signed before a key rotation is verified with the older key file, not the newest.

To check the scan attestation as well:

Terminal window
cosign verify-attestation \
--key sencai-acme-cosign.pub \
--type vuln \
--insecure-ignore-tlog=true \
--new-bundle-format=false \
git.sencai.space/acme/api@sha256:<digest>

The attestation is only present once the first scan has finished, and there is one per platform image. It carries the findings, the scanner and vulnerability data versions, and the time of the scan. If the image has more than ten thousand findings, the attestation lists the first ten thousand by severity and says so. It is refreshed on the first scan and on rescans you start yourself with Scan again, not by the automatic weekly rescan, so check its scan time before relying on it as current. Because it holds the findings, the attestation can only be downloaded by people with access to security findings.

Verifying needs a registry credential that can pull (see Access). If you only want to check a signature and have no registry access, use the offline check below.

  • --insecure-ignore-tlog=true - cosign normally expects a signature to be recorded in a public transparency log. Sencai does not publish to one: it would make the name of every private image public. The name of the flag sounds alarming, but what protects you here is your organization’s key, which you downloaded yourself and which only Sencai can sign with. Nothing about your images leaves the platform.
  • --new-bundle-format=false - Sencai stores signatures the way cosign 2 did, as tags next to the image, not as the newer bundles in cosign 3’s default format. Both cosign 2.6 and cosign 3 verify this format with the flag. cosign 3 prints a warning that the flag is deprecated and that the newer format will be the only one in future versions; the verification still works today. If a later cosign release stops supporting the older format, verify with a release that still does (2.6.x, or the 3.x you have verified with).

An auditor or a customer who has no registry credential can still verify a signature, because the signed material is available from the app.

  1. On the image page, in the Prove what you deployed card, download the signature material for the digest: payload.json (the signed payload) and sig.b64 (the signature), and the public key.
  2. Verify the signature with your public key:
Terminal window
cosign verify-blob \
--key sencai-acme-cosign.pub \
--signature sig.b64 \
--insecure-ignore-tlog=true \
payload.json
  1. Open payload.json and compare critical.image.docker-manifest-digest with the digest your runtime reports (next section). They must be identical.

The first step proves the payload was signed by your key; the second step proves the payload is about the image that is running. You need both. Download the material from the page of the digest you are comparing: for a multi-platform image that is the digest your runtime reports, which may be the index or one of its platform images (Sencai signs both).

If the image has a scan attestation and you can read security findings, the same card offers envelope.json, the signed attestation, so an auditor can keep it with the rest of the evidence.

Compare the signed digest with what your servers actually run. Look at the image of the running container, not at the tag you started it from: a tag can point at a newer image than the one running.

Docker

Terminal window
docker inspect --format '{{.Image}}' <container>
docker image inspect <image-id-from-above> --format '{{json .RepoDigests}}'

Kubernetes

Terminal window
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[*].imageID}'

The value after @ is the digest. Runtimes usually report the digest that the image reference resolved to when it was pulled. For a multi-platform image that is usually the digest of the index, but some runtimes report the digest of the platform image they pulled (for example linux/amd64). Sencai signs both, so download the signature material for whichever digest your runtime reports; if you take the other one, the digests will not match even though the image is the same.

If you report deployments to Sencai with the image reference and digest, the Deployments timeline shows the image’s signature and scan state next to the deployment record. Pull by digest in your manifests (image: git.sencai.space/acme/api@sha256:...) so a deployment runs exactly the content you verified, even if a tag is moved later. An image that only a digest points to is not rescanned automatically; use Scan again on it from time to time.

Servers that Sencai deploys verify it for you

Section titled “Servers that Sencai deploys verify it for you”

When you deploy an image of your registry to a new instance, the server checks the image’s signature itself before it runs anything. It uses your organization’s public key (the one this page tells you to download) and the digest that was ordered, with the same cosign verify check as above. If the check fails, nothing starts, the deploy shows The signature check failed on the server, and the members with access to security findings are notified. Only a signed version can be chosen in the wizard in the first place.

That check happens once, at deploy time. It does not keep watching the server, so use the commands above to check a running server later.

What you see What it means What to do
Signing… Normal for a minute or two after a push Wait
Not signed — pushed by an account that may not push here The pusher had no permission to push at that time. For a push from a hosted CI job this also covers a push that cannot be tied to the live job it came from, or whose triggering person may no longer push. The image is never signed, and the members who have access to security findings are notified Push the image again from an authorized account, from your CI credential, or from a new run of the job
Signature removed — re-signing / Signature changed — re-signing Someone deleted or replaced the signature objects that sit next to the image (tags that start with sha256- and end in .sig or .att). Sencai usually notices within 15 minutes and is attaching the signature again Nothing. A changed signature is also recorded in the audit log and the members with access to security findings are notified. Do not delete those tags yourself
Signing failed (<reason>), retrying at <time> / Gave up after N attempts Signing hit a temporary problem, such as the signing service being unavailable Wait for the retry, or use Sign again once the reason is resolved
Not signed — signing key check failed The key on record for your organization no longer matches the key Sencai signs with. Sencai stops signing for your organization and the security contacts are notified Contact support
Signing is not enabled in this environment The environment you use has not switched signing on Not an image problem

Your organization’s key is created automatically the first time an image of yours is signed, and the private half never leaves Sencai’s secret store: it is not exportable. Only the public half is available to you.

If Sencai rotates your key, the new version is added and published next to the old ones. Signatures made earlier stay valid and still verify with the version they were made with; the signed payload names the fingerprint of the version used. Keep every version you download.

If you delete the organization, its signatures and the records of its signing keys are deleted with it, together with the rest of its registry data. Download the public keys and any signature material you want to keep before deleting; nothing is taken for you.

Reading images, downloading the key and downloading signature material need the registry Read permission, which every role including Viewer and Auditor has by default; the signed attestation needs access to security findings as well. Sign again needs Update. See Who can do what.