About container image digests

This page describes image digests, including what image digests are, how tofind them, and how to enforce their use in Kubernetes clusters. This pageis intended for developers and operators who build and deploy containerimages.

Acontainer image digest uniquely and immutably identifies a container image. When you deploy images bydigest, you avoid the downsides of deploying byimage tags.

The commands on this page assume that you have access to a Linux or macOSshell environment with tools such as theGoogle Cloud CLI,Docker, cURL,jq,andpack already installed. Or, you can useCloud Shell,which has these toolspre-installed.

Container images and image tags

When working with container images, you need a way to refer to the images thatyou use.Image tags are a common way of referring to different revisions of an image. A commonapproach is to tag images with a version identifier at build time. For example,v1.0.1 could refer to a version that you call1.0.1.

Tags make image revisions easy to look up by human-readable strings. However,tags are mutable references, which means the image referenced by a tag canchange, as illustrated in the following diagram:

Image tag pointing to an outdated image.

As the previous diagram shows, if you publish a new image using the same tag asan existing image, the tag stops pointing to the existing image and startspointing to your new image.

Disadvantages of image tags

Because tags are mutable, they have the following disadvantages when you usethem to deploy an image:

  • In Kubernetes, deploying by tag can result in unexpected results. Forexample, assume that you have an existing Deployment resource thatreferences a container image by tagv1.0.1. To fix a bug or make a smallchange, your build process creates a new image with the same tagv1.0.1.New Pods that are created from your Deployment resource can end up usingeither the old or the new image, even if you don't change your Deploymentresource specification. This problem also applies to other Kubernetesresources such as StatefulSets, DaemonSets, ReplicaSets, and Jobs.

  • If you use tools to scan or analyze images, results from these toolsare only valid for the image that was scanned. To ensure that you deploythe image that was scanned, you cannot rely on the tag because the imagereferred by the tag might have changed.

  • If you useBinary Authorization withGoogle Kubernetes Engine (GKE),tag-based deployment is disallowed because it's impossible to determine theexact image that is used when a Pod is created.

When you deploy your images, you can use an image digest to avoid thedisadvantages of using tags. You can still add tags to your images if you like,but you don't have to do so.

Structure of an image

An image consists of the following components:

These components are illustrated in the following diagram:

Components of an image showing details for an image manifest, a configuration object, file system layers, and an image index.

The preceding image shows additional detail about image components:

  • The image manifest is a JSON document that contains a reference to theconfiguration object, the file system layers, and optional metadata.
  • The image manifest references the configuration object and each of thefile system layers using theirdigest attributes. The value of adigest attribute is a cryptographic hash of the contents that the digestrefers to, typically calculated using theSHA-256 algorithm.
  • The digest values are used to construct immutable addresses to theobjects. This process is calledcontent-addressable storage,and it means that you can retrieve image manifests, image indexes,configuration objects, and layers based on their digests.
  • The image digest is the hash of the image index or image manifest JSONdocument.
  • The configuration object is a JSON document that definesproperties of the image,such as the CPU architecture, entrypoint, exposed ports, and environmentvariables.
  • The file system layer array defines the order that the container runtimeuses to stack the layers. The layers are distributed astar files,typically compressed using thegzip utility.
  • The optional image index, sometimes referred to as themanifest list,refers to one or more image manifests. The reference is the digest of theimage manifest. An image index is useful when you produce multiple relatedimages for differentplatforms,such asamd64 andarm64 architectures.

For more information, see the sectionExploring image manifests, digests, and tags.

Finding image digests

To use image digests for deployment, you must first find the digest. Then, youcan use the digest with your deployment command or include it in your Kubernetesmanifests.

You can get the digest of an image in various ways, depending on your currentsituation. The following sections contain examples for different products andtools.

In the following sections, run the commands in Cloud Shell or in ashell environment with tools such as the gcloud CLI, Docker, cURL,andjq already installed.

Artifact Registry

Container Registry

Caution: Container Registry is deprecated. Effective March 18, 2025, Container Registry is shut down, and writing images to Container Registry is unavailable. For details on the deprecation and how to migrate to Artifact Registry, seeContainer Registry deprecation.

  • For images stored inContainer Registry,you can use thegcloud container images describe command to get the digest for an image by providing the name and a tag. Use the--format flag to only display the digest:

    gcloudcontainerimagesdescribe\gcr.io/google-containers/pause-amd64:3.2\--format'value(image_summary.digest)'

    The output looks similar to the following, though your digest value mightdiffer:

    sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108

Cloud Build

For images built usingCloud Build,you can get the image digest by using thegcloud builds describe command with the--format flag. This approach works regardless of which registryyou used to publish your image.

  • For an already completed build, do the following:

    1. Get a list of builds for your project:

      gcloudbuildslist

      Make a note of aBUILD_ID.

    2. Get the image digest:

      gcloud builds describeBUILD_ID \    --format 'value(results.images[0].digest)'

      ReplaceBUILD_ID with the unique ID thatCloud Build assigned to your build.

  • Get the image name and digest for the latest build fromCloud Build for your current project:

    gcloudbuildsdescribe\$(gcloudbuildslist--limit1--format'value(id)')\--format'value[separator="@"](results.images[0].name,results.images[0].digest)'
  • If your build produced multiple images, filter the output and get thedigest of one of the images:

    gcloud builds describeBUILD_ID --format json \    | jq -r '.results.images[] | select(.name=="YOUR_IMAGE_NAME") | .digest'

    ReplaceYOUR_IMAGE_NAME with the name of one of theimages from yourcloudbuild.yaml file.

  • If you submit a build to Cloud Build using thegcloud builds submit command,you can capture the image digest from the output in an environment variable:

    IMAGE_DIGEST=$(gcloud builds submit \    --format 'value(results.images[0].digest)' | tail -n1)

Cloud Native Buildpacks

  • If you useCloud Native Buildpacks and the Google Cloud builder to build and publish images, you cancapture the image name and digest by using the--quiet flag with thepack command:

    pack build --builder gcr.io/buildpacks/builder:v1 --publish --quiet \LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \    > image-with-digest.txt

    Replace the following:

    • LOCATION: the regional or multi-regionallocation of your repository
    • PROJECT_ID: yourGoogle Cloud project ID
    • REPOSITORY: your repository name
    • IMAGE: your image name

    The fileimage-with-digest.txt contains the image name and digest.

    Use the--tag flag if you want to add tags to the image.

Docker client

  • Themanifest subcommand of thedocker command line client can fetch image manifests and manifest listsfrom container image registries.

    Get the digest from the manifest list of the imageregistry.k8s.io/pause:3.9, for theamd64 CPU architecture and thelinux operating system:

    dockermanifestinspect--verboseregistry.k8s.io/pause:3.9|\jq-r'iftype=="object"then.Descriptor.digestelse.[]|select(.Descriptor.platform.architecture=="amd64"and.Descriptor.platform.os=="linux")|.Descriptor.digestend'

    The output looks similar to the following:

    sha256:8d4106c88ec0bd28001e34c975d65175d994072d65341f62a8ab0754b0fafe10
  • For images that are stored in your localDocker daemon,and that have been either pulled from or pushed to an image registry,you can use the Docker command line tool to get the image digest:

    1. Pull the image to your localDocker daemon:

      dockerpulldocker.io/library/debian:bookworm
    2. Get the image digest:

      dockerinspectdocker.io/library/debian:bookworm\|jq-r'.[0].RepoDigests[0]'\|cut-d'@'-f2

      The output looks similar to the following, though your digest valuemay differ:

      sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b
  • List all images and digests in your local Docker daemon:

    docker images --digests

    The output shows digests for images that have a digest value. Images onlyhave a digest value if they were pulled from or pushed to an image registry.

crane andgcrane

You can use the open sourcecrane andgcrane command-line tools toget the digest of an image without pulling the image to a local Docker daemon.

  1. Downloadcrane andgcrane to your current directory:

    VERSION=$(curl-sLhttps://api.github.com/repos/google/go-containerregistry/releases/latest|jq-r.tag_name)curl-L"https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_$(uname -s)_$(uname -m).tar.gz"|tar-zxf-cranegcrane
  2. Get image digests:

    ./gcrane digest gcr.io/distroless/static-debian11:nonroot

    crane andgcrane have other features that are outside the scopeof this page. For more information, see the documentation forcrane andgcrane.

Enforcing the use of image digests in Kubernetes deployments

If you want to enforce using digests for images that you deploy to yourKubernetes clusters, you can usePolicy Controller orOpen Policy Agent (OPA) Gatekeeper.Policy Controller is built from the OPA Gatekeeper open source project.

Policy Controller and OPA Gatekeeper both build on theOPA policy engine.Policy Controller and OPA Gatekeeper provide aKubernetes validating admission webhook to enforce policies, andcustom resource definitions (CRDs) forconstraint templates andconstraints.

Constraint templates contain policy logic that is expressed using a high-leveldeclarative language calledRego.The following is a constraint template that validates that containers,init containers,andephemeral containers in a Kubernetes resource specification use images with digests:

apiVersion:templates.gatekeeper.sh/v1kind:ConstraintTemplatemetadata:name:k8simagedigestsannotations:metadata.gatekeeper.sh/title:"ImageDigests"metadata.gatekeeper.sh/version:1.0.1description:>-Requires container images to contain a digest.https://kubernetes.io/docs/concepts/containers/images/spec:crd:spec:names:kind:K8sImageDigestsvalidation:openAPIV3Schema:type:objectdescription:>-Requires container images to contain a digest.https://kubernetes.io/docs/concepts/containers/images/properties:exemptImages:description:>-Any container that uses an image that matches an entry in this list will be excludedfrom enforcement. Prefix-matching can be signified with `*`. For example:`my-image-*`.It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name)in order to avoid unexpectedly exempting images from an untrusted repository.type:arrayitems:type:stringtargets:-target:admission.k8s.gatekeeper.shrego:|package k8simagedigestsimport data.lib.exempt_container.is_exemptviolation[{"msg": msg}] {container := input.review.object.spec.containers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image])}violation[{"msg": msg}] {container := input.review.object.spec.initContainers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image])}violation[{"msg": msg}] {container := input.review.object.spec.ephemeralContainers[_]not is_exempt(container)not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image])}libs:-|package lib.exempt_containeris_exempt(container) {exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", [])img := container.imageexemption := exempt_images[_]_matches_exemption(img, exemption)}_matches_exemption(img, exemption) {not endswith(exemption, "*")exemption == img}_matches_exemption(img, exemption) {endswith(exemption, "*")prefix := trim_suffix(exemption, "*")startswith(img, prefix)}

The preceding policy contains a regular expression as input to there_match function.This regular expression matches the container image digest, and it is based onthedigest format in the Open Container Initiative Image Specification.

Constraints apply the policy to Kubernetes resources by matching againstattributes such askind andnamespace. The following example constraintapplies the policy from the constraint template to allPod resources in thedefault namespace.

apiVersion:constraints.gatekeeper.sh/v1beta1kind:K8sImageDigestsmetadata:name:container-image-must-have-digestspec:match:kinds:-apiGroups:[""]kinds:["Pod"]namespaces:-"default"

After you create the constraint template and the constraint, any new pods inthedefault namespace must use image digests to reference container images.

For the full example, see theimagedigests policy in the Gatekeeper policy library.

About image manifests, digests, and tags

In this section, you learn how to explore existing images in registries usingcommand-linetools such ascurl anddocker. Run the commands in Cloud Shell orin a shell environment with tools such as the gcloud CLI, Docker,cURL, andjq already installed. The following commands use public images inArtifact Registry.

  • Get the manifest of the imagegcr.io/google-containers/pause-amd64:3.2 by using cURL and themanifest URL:

    curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2

    The output is similar to the following:

    {   "schemaVersion": 2,   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",   "config": {      "mediaType": "application/vnd.docker.container.image.v1+json",      "size": 759,      "digest": "sha256:80d28bedfe5dec59da9ebf8e6260224ac9008ab5c11dbbe16ee3ba3e4439ac2c"   },   "layers": [      {         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",         "size": 296534,         "digest": "sha256:c74f8866df097496217c9f15efe8f8d3db05d19d678a02d01cc7eaed520bb136"      }   ]}

    Theconfig section has a digest attribute, and you can use this valueto retrieve the configuration object. Similarly, each layer has adigestattribute that you can use to retrieve the tar file for that layer.

  • If the image includes the optional image index, an HTTPGET requestto the manifest URL using a tag returns the image index instead of theimage manifest.

    Get the image index of the imagegcr.io/google-containers/pause:3.2:

    curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2

    The output is similar to the following:

    {   "schemaVersion": 2,   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",   "manifests": [      {         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",         "size": 526,         "digest": "sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108",         "platform": {            "architecture": "amd64",            "os": "linux"         }      },      {         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",         "size": 526,         "digest": "sha256:bbb7780ca6592cfc98e601f2a5e94bbf748a232f9116518643905aa30fc01642",         "platform": {            "architecture": "arm",            "os": "linux",            "variant": "v7"         }      },      {         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",         "size": 526,         "digest": "sha256:31d3efd12022ffeffb3146bc10ae8beb890c80ed2f07363515580add7ed47636",         "platform": {            "architecture": "arm64",            "os": "linux"         }      },      {         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",         "size": 526,         "digest": "sha256:7f82fecd72730a6aeb70713476fb6f7545ed1bbf32cadd7414a77d25e235aaca",         "platform": {            "architecture": "ppc64le",            "os": "linux"         }      },      {         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",         "size": 526,         "digest": "sha256:1175fd4d728641115e2802be80abab108b8d9306442ce35425a4e8707ca60521",         "platform": {            "architecture": "s390x",            "os": "linux"         }      }   ]}
  • Filter the result to extract the image digest for the platform that youwant. Get the digest of the image manifest for theamd64 CPU architectureand thelinux operating system:

    curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2 | \    jq -r '.manifests[] | select(.platform.architecture=="amd64" and .platform.os=="linux") | .digest'

    The filtering in this command mimics how container runtimes,such ascontainerd,select the image that matches the target platform from the image index.

    The output is similar to the following:

    sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108

    Theimage digest is the result of applying acollision-resistant hash to the image index or image manifest, typically theSHA-256 algorithm.

  • Get the digest of the imagegcr.io/google-containers/pause-amd64:3.2:

    curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \    | shasum -a 256 \    | cut -d' ' -f1

    The output is similar to the following:

    4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108

    You can reference this image using the image digest value as follows:

    gcr.io/google-containers/pause-amd64@sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
  • Using thecontent-addressable storage concept, get the image manifest by using the digest as a reference:

    curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
  • Many container image registries return the digest of manifests, imageindexes, configuration objects, and file system layers in theDocker-Content-Digest header in response to HTTPHEAD requests. Get thedigest of the image index of the imagegcr.io/google-containers/pause-amd64:3.2:

    curl -s --head https://gcr.io/v2/google-containers/pause/manifests/3.2 \    | grep -i Docker-Content-Digest \    | cut -d' ' -f2

    The output is similar to the following:

    sha256:927d98197ec1141a368550822d18fa1c60bdae27b78b0c004f705f548c07814f

    TheDocker-Content-Digest header isnot mandated by the Open Container Initiative Distribution specifications,so this approach might not work with all container image registries. Youcan use it withArtifact Registry andContainer Registry.

  • To retrieve an image configuration object using the digest value fromthe image manifest, do the following:

    1. Get the configuration digest:

      CONFIG_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \    | jq -r '.config.digest')
    2. Use the configuration digest to retrieve the configurationobject, and usejq to format the output to make it easier to read:

      curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$CONFIG_DIGEST \    | jq

      The output is similar to the following:

      {  "architecture": "amd64",  "config": {    "Env": [      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"    ],    "Entrypoint": [      "/pause"    ],    "WorkingDir": "/",    "OnBuild": null  },  "created": "2020-02-14T10:51:50.60182885-08:00",  "history": [    {      "created": "2020-02-14T10:51:50.60182885-08:00",      "created_by": "ARG ARCH",      "comment": "buildkit.dockerfile.v0",      "empty_layer": true    },    {      "created": "2020-02-14T10:51:50.60182885-08:00",      "created_by": "ADD bin/pause-amd64 /pause # buildkit",      "comment": "buildkit.dockerfile.v0"    },    {      "created": "2020-02-14T10:51:50.60182885-08:00",      "created_by": "ENTRYPOINT [\"/pause\"]",      "comment": "buildkit.dockerfile.v0",      "empty_layer": true    }  ],  "os": "linux",  "rootfs": {    "type": "layers",    "diff_ids": [      "sha256:ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770"    ]  }}
  • To retrieve file system layers using digest values from the imagemanifest, do the following:

    1. Get the digest of the layer that you want to retrieve:

      LAYER_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \    | jq -r '.layers[0].digest')
    2. Use the layer digest to retrieve the layer tar file, and listthe contents:

      curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$LAYER_DIGEST \    | tar --list

      This layer has only one file, calledpause.

  • To look up tags associated with an image digest, do the following:

    1. Define the digest that you want to look up:

      IMAGE_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \    | shasum -a 256 \    | cut -d' ' -f1)

      TheIMAGE_DIGEST environment variable contains the digest of the imagereferenced by the tag3.2.

    2. Use theimage tags list endpoint,/tags/list,to list tag information, and extract the tags for the digest value:

      curl -s "https://gcr.io/v2/google-containers/pause-amd64/tags/list?n=1" \    | jq ".manifest.\"sha256:$IMAGE_DIGEST\".tag"

      The output is similar to the following:

      [  "3.2"]
  • To get the manifest of an image from a Artifact Registry container imagerepository by using cURL, include anaccess token in theAuthorization request header:

    curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \    https://LOCATION-docker.pkg.dev/v2/PROJECT_ID/REPOSITORY/IMAGE/manifests/DIGEST

    Replace the following:

    • LOCATION: the regional or multi-regionallocation of your repository
    • PROJECT_ID: yourGoogle Cloud project ID
    • REPOSITORY: your repository name
    • IMAGE: your image name
    • DIGEST: your image digest in the formatsha256:DIGEST_VALUE

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-18 UTC.