Container images are usually referenced by tag, maybe a nice semantic version, or maybe a git commit sha. Whatever the value, a tag is still a mutable thing, today it might point at one thing, a force push later, and tomorrow it points at something else.
To get around that we can reference images (or other artifacts) by digest, a content hash which can only refer to a single thing. To resolve a mutable tag to a digest, we have several options:
crane, or the gcrane variant, are command line tools for general registry/image manipulation.
1$ gcrane digest golang:alpine
2sha256:ee2f23f1a612da71b8a4cd78fec827f1e67b0a8546a98d257cca441a4ddbebcb
cosign is a tool primarily for signing images/artifacts,
but it notably complains if you try to sign things by tag,
as you might not be signing the thing you thought you were signing.
It has a triangulate
subcommand for finding where the signature might be,
but we can use that to extract the digest.
1$ cosign triangulate golang:alpine
2index.docker.io/library/golang:sha256-ee2f23f1a612da71b8a4cd78fec827f1e67b0a8546a98d257cca441a4ddbebcb.sig
3
4$ cosign triangulate golang:alpine | tr ':-' '@:' | sed 's/\.sig//'
5index.docker.io/library/golang@sha256:ee2f23f1a612da71b8a4cd78fec827f1e67b0a8546a98d257cca441a4ddbebcb
6
7$ cosign triangulate golang:alpine | sed -E 's/.*sha256-(.*).sig/\1/'
8ee2f23f1a612da71b8a4cd78fec827f1e67b0a8546a98d257cca441a4ddbebcb
docker... just remember to pull the image first, since it operates locally instead of directly on remote registries like crane and cosign.
1$ docker image inspect golang:alpine | jq -r '.[] | .RepoDigests[]'
2golang@sha256:ee2f23f1a612da71b8a4cd78fec827f1e67b0a8546a98d257cca441a4ddbebcb