Signing container images ensures their integrity and authenticity, but verifying that signature can be surprisingly complex.
Let’s see this in action. Imagine you’ve just pulled an image:
podman pull docker.io/library/alpine:latest
Now, you want to verify its signature. If the image was signed, you might expect a simple command to reveal everything. But the reality is more nuanced. You need to know how it was signed and what trust model you’re operating under.
Podman uses skopeo under the hood for many of these operations, and understanding skopeo’s capabilities is key. The core idea is that an image signature is a cryptographic artifact that proves the image hasn’t been tampered with since it was signed, and that it came from a specific, trusted source. This trust is established through public-key cryptography. A signer uses their private key to sign the image manifest, and you use their corresponding public key (or a trusted intermediary) to verify.
Here’s the mental model:
- Image Storage: Podman stores images locally. When you pull an image, it lands in its own storage.
- Signature Storage: Signatures aren’t part of the image layers themselves. They are separate metadata, often stored alongside the image in the registry or fetched independently.
- Trust Model: How do you decide if a signature is trustworthy?
- Direct Trust: You have the signer’s public key, and you tell Podman/skopeo to trust it. This is common for internal registries or images you sign yourself.
- Notary/Policy: A central service (like Notary, though often not used directly by end-users of public registries) or a policy engine dictates which signatures are acceptable. For public registries like Docker Hub, this is often implicit – if it’s on Docker Hub and signed, it’s assumed to be from the publisher, but direct verification of who signed it with what key is not always straightforward or even exposed.
- Verification Process: Podman (via
skopeo) needs to:- Locate the image manifest.
- Locate the associated signature(s).
- Obtain the public key corresponding to the signature’s private key.
- Perform the cryptographic verification.
- Compare the verified identity of the signer against your configured trust policies.
Let’s say you have an image myregistry.com/myimage:latest that you know was signed by signer@example.com using a specific key. To verify this, you’d typically use skopeo.
First, you need the signature. If the registry supports it, skopeo copy can fetch it. But more often, you’re verifying an existing local copy.
The command you’d use is skopeo standalone-sign (which is how you would sign) and then skopeo copy --sign-by <key-id> or skopeo copy --all --dest-creds ... to pull signed images, but for verification, it’s often about checking the manifest and the associated signature data.
A more direct approach for verification when you have the image locally and know the expected signer is to inspect the image’s metadata. However, Podman’s direct user-facing commands for verifying a specific signature against a specific key are less prominent than the signing commands themselves. The verification is often implicit in podman run if you’ve configured trust policies.
To manually verify an image signature with a known public key, you’d typically use skopeo. Suppose your public key is ~/.ssh/mykey.pub and the image is docker://localhost:5000/myimage:latest.
You would first need to ensure the image is signed. If it is, you can try to copy it while specifying the signing key:
# This command actually *copies* and verifies if the source is signed
# and you're specifying the key to use for verification.
# It's a bit of a dual-purpose command.
skopeo copy docker://localhost:5000/myimage:latest docker-daemon:myimage:latest --sign-by signer@example.com --src-creds ... --dest-creds ...
If this command succeeds without error, it implies the signature was valid for the specified signer. If it fails, you’ll get an error indicating a signature mismatch or an unknown key.
A more explicit verification, if you had the signature file (e.g., manifest.json.sig), would involve gpg or similar tools, but Podman/Skopeo abstract this.
The one thing most people don’t realize is that podman run itself performs signature verification if you have configured trust policies. For example, if you have a policy.json file that dictates that images from myregistry.com must be signed by a specific key, podman run will automatically check this before starting a container. You don’t always need to explicitly call a verify command.
The next step is understanding how to implement and manage these trust policies for automated verification.