verify¶
Verify that a stored image signature matches the current manifest digest. Use this as a gate in CI/CD pipelines to ensure only signed images are deployed.
The reference must include an explicit tag. Both s3:// and local:// references are supported.
Flags¶
| Flag | Default | Description |
|---|---|---|
--key |
— | Verification key reference (required). See Key formats |
--output |
text |
Output format: text or json |
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Signature is valid |
1 |
Signature is missing or cryptographically invalid |
2 |
Infrastructure error (cannot reach S3, KMS, etc.) |
Separating 1 (supply-chain failure) from 2 (infrastructure failure) lets CI pipelines distinguish between a broken build gate and a broken environment.
Key formats¶
| Format | Example |
|---|---|
| AWS KMS alias | awskms:///alias/release-signer |
| AWS KMS ARN | awskms:///arn:aws:kms:us-east-1:123456789012:key/mrk-abc |
| Local public key file | ./cosign.pub |
| Local private key file | ./cosign.key (public key is derived from it) |
| HashiCorp Vault | hashivault://vault.example/v1/transit/keys/ci-signer |
Note the triple slash (awskms:///) — required by the cosign KMS reference format.
Examples¶
# Verify with AWS KMS
s3lo verify s3://my-bucket/myapp:v1.0 --key awskms:///alias/release-signer
# Verify with a local public key file
s3lo verify s3://my-bucket/myapp:v1.0 --key cosign.pub
# Verify a local:// image
s3lo verify local://./local-s3/alpine:latest --key cosign.pub
# CI gate — exits 1 on failure, 2 on infrastructure error
s3lo verify s3://my-bucket/myapp:v1.0 --key awskms:///alias/release-signer \
&& echo "Deploy approved" || echo "Deploy blocked"
# Machine-readable output
s3lo verify s3://my-bucket/myapp:v1.0 --key cosign.pub --output json
Output¶
Success:
✓ Verified myapp:v1.0
Digest: sha256:25109184c71b...
Signed: 2026-04-12T19:21:10Z
Key: awskms:///alias/release-signer
Failure (missing signature):
Failure (tampered image):
✗ Verification FAILED for myapp:v1.0
manifest changed: signed sha256:25109184..., current sha256:deadbeef...
JSON output (--output json):
{
"verified": true,
"digest": "sha256:25109184c71b...",
"keyRef": "awskms:///alias/release-signer",
"keyID": "3b780f64bd6940e1",
"signedAt": "2026-04-12T19:21:10Z"
}
On failure, verified is false and reason is set:
{
"verified": false,
"reason": "no signature found for key cosign.pub",
"digest": "sha256:25109184c71b...",
"keyRef": "cosign.pub",
"keyID": "21b44047667b31d3"
}
CI integration¶
GitHub Actions¶
- name: Verify image signature
run: |
s3lo verify s3://my-bucket/myapp:${{ github.sha }} \
--key awskms:///alias/release-signer \
--output json | tee verify-result.json
env:
AWS_REGION: us-east-1
The --output json result can be saved as a build artifact for audit evidence.
Deployment gate¶
#!/bin/bash
s3lo verify s3://my-bucket/myapp:${VERSION} --key awskms:///alias/release-signer
if [ $? -ne 0 ]; then
echo "Image verification failed. Refusing deployment."
exit 1
fi
kubectl set image deployment/myapp myapp=...
What is verified¶
verify checks three things:
- Signature exists — a
.jsonfile for this key's fingerprint is present atmanifests/<image>/<tag>/signatures/<keyid>.json - Digest matches — the digest stored in the signature matches the current manifest's SHA-256
- Signature is valid — the cryptographic signature bytes verify against the stored digest and the provided key
If any check fails, the command exits 1 with a descriptive message.
Multiple signers¶
If an image has been signed by multiple keys, each key produces its own signature file. Run verify once per key you want to check:
s3lo verify s3://my-bucket/myapp:v1.0 --key awskms:///alias/ci-signer
s3lo verify s3://my-bucket/myapp:v1.0 --key awskms:///alias/release-signer
Use s3lo inspect to see which keys have signed an image.
See also: s3lo sign, s3lo inspect