# Verifying Chainguard Containers and Metadata Signatures with Cosign

URL: https://edu.chainguard.dev/chainguard/chainguard-images/how-to-use/verifying-chainguard-images-and-metadata-signatures-with-cosign.md
Last Modified: July 23, 2025
Tags: Chainguard Containers

Learn how to verify Chainguard Container signatures and attestations with Cosign for supply chain security, ensuring image authenticity and integrity

Chainguard signs all container images and their attestations (including SBOMs) to ensure supply chain security and enable verification of image authenticity. These cryptographic signatures allow you to confirm that images come from Chainguard and haven&rsquo;t been tampered with, while attestations provide detailed information about image contents and build provenance.
This guide outlines how you can use Cosign to download and verify container image signatures and attestations.
Prerequisites The following examples require Cosign and jq to be installed on your machine in order to download and verify image attestations.
Registry and Tags for Chainguard Containers Attestations are provided per image build, so you&rsquo;ll need to specify the correct tag and registry when pulling attestations from an image with cosign. This guide works with Chainguard&rsquo;s public and private registries:
cgr.dev/chainguard: The public registry contains Chainguard&rsquo;s Free container images, which typically comprise the :latest versions of an image. cgr.dev/YOUR-ORGANIZATION: A private/dedicated registry contains your organization&rsquo;s Production container images, which include all versioned tags of an image and special images that are not available in the public registry (including FIPS images and other custom builds). The commands listed on this page will default to the :latest tag, but you can specify a different tag to fetch attestations for.
Chainguard&rsquo;s Signing Identities Chainguard uses an identity associated with its official GitHub account to sign images in the public registry that contains the Free tier of images.
For private images, Chainguard signs all images in your private registry with one of two different identities in your organization:
The catalog_syncer identity is used to sign images that have been imported directly from the Chainguard Containers catalog. The apko_builder identity is used to sign any images that have been customized for your organization, such as those built with Custom Assembly. These identities are created and added to every verified Chainguard organization automatically.
To follow along with the Private Registry examples in this guide, you will need the unique identifier paths (UIDPs) of these Chainguard identities. To this end, create a few environment variables, the first of which should point to the name of your Chainguard organization:
PARENT=your-organizationNext, create two more variables to hold the UIDPs of your organization&rsquo;s catalog_syncer and apko_builder identities, respectively:
CATALOG_SYNCER=$(chainctl iam account-associations describe $PARENT -o json | jq -r &#39;.[].chainguard.service_bindings.CATALOG_SYNCER&#39;) APKO_BUILDER=$(chainctl iam account-associations describe $PARENT -o json | jq -r &#39;.[].chainguard.service_bindings.APKO_BUILDER&#39;)The Private Registry examples in this guide will include these environment variables, allowing you to verify that they were used to sign the given image.
Be aware that you can also find these values in the Chainguard Console. After logging in, click on Settings, and then Users. From there, scroll or search for either catalog_syncer or apko_builder and click on its row to find the identity&rsquo;s UIDP:
Verifying Container Image Signatures Chainguard Containers are signed using Sigstore and you can check the included signatures using cosign. The cosign verify command will pull detailed information about all signatures found for the provided image.
Public Registry IMAGE=go cosign verify \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ --certificate-identity=https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main \ cgr.dev/chainguard/${IMAGE} | jq Private/Dedicated Registry IMAGE=go cosign verify \ --certificate-oidc-issuer=https://issuer.enforce.dev \ --certificate-identity-regexp=&#34;https://issuer.enforce.dev/(${CATALOG_SYNCER}|${APKO_BUILDER})&#34; \ cgr.dev/${PARENT}/${IMAGE} | jqBe aware that you will need to change the IMAGE environment variable to reflect a container image your organization is entitled to.
Note: The environment variables used in this command (other than ${IMAGE}) were created in the previous section.
By default, this command will fetch signatures for the :latest tag. If you&rsquo;d like, you can specify the tag you want to fetch signatures for:
IMAGE=go TAG=1.23.8 cosign verify \ --certificate-oidc-issuer=https://issuer.enforce.dev \ --certificate-identity-regexp=&#34;https://issuer.enforce.dev/(${CATALOG_SYNCER}|${APKO_BUILDER})&#34; \ cgr.dev/${PARENT}/${IMAGE}:${TAG} | jq Downloading Container Attestations Attestations are signed metadata about the artifact, which can include SBOMs, vulnerability scans, or other custom predicates.
The attestations for a container image can be obtained and verified using Cosign or directly in the Chainguard Console. See How to retrieve attestations and SBOMs for Chainguard Containers for more information.
Public Registry IMAGE=go cosign download attestation \ --predicate-type=https://spdx.dev/Document \ --platform=linux/amd64 \ cgr.dev/chainguard/${IMAGE} | jq -r .payload | base64 -d | jq .predicate Private/Dedicated Registry IMAGE=go cosign download attestation \ --predicate-type=https://spdx.dev/Document \ --platform=linux/amd64 \ cgr.dev/${PARENT}/${IMAGE} | jq -r .payload | base64 -d | jq .predicate Verifying Image Attestations You can use the cosign verify-attestation command to check the signatures of the desired container image attestations:
Public Registry IMAGE=go cosign verify-attestation \ --type https://spdx.dev/Document \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ --certificate-identity=https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main \ cgr.dev/chainguard/${IMAGE} | jqThis will pull in the signature for the attestation specified by the --type parameter, which in this case is the SPDX attestation for SBOMs. You will receive output that verifies the SBOM attestation signature in Cosign&rsquo;s transparency log:
Verification for cgr.dev/chainguard/go -- The following checks were performed on each of these signatures: - The cosign claims were validated - Existence of the claims in the transparency log was verified offline - The code-signing certificate was verified using trusted certificate authority certificates Certificate subject: https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main Certificate issuer URL: https://token.actions.githubusercontent.com GitHub Workflow Trigger: schedule GitHub Workflow SHA: da283c26829d46c2d2883de5ff98bee672428696 GitHub Workflow Name: .github/workflows/release.yaml GitHub Workflow Trigger chainguard-images/images GitHub Workflow Ref: refs/heads/main ... Private/Dedicated Registry IMAGE=go cosign verify-attestation \ --type https://spdx.dev/Document \ --certificate-oidc-issuer=https://issuer.enforce.dev \ --certificate-identity-regexp=&#34;https://issuer.enforce.dev/(${CATALOG_SYNCER}|${APKO_BUILDER})&#34; \ cgr.dev/${PARENT}/${IMAGE} | jq Note About the Examples in this Guide The examples in this guide invariably pass command output through jq, a JSON processor. This is helpful, as it makes the output more easily readable.
However, if you&rsquo;re running these commands in a script, this can cause problems if validation fails. For example, if Cosign returns an error but it is passed into jq, then jq will overwrite the exit codes from Cosign, causing them to be silently ignored.
To avoid this problem, you could include either or both of the following set options in your script:
set -e ensures that your script exits with an error if any of the commands in your script exit with an error. set -o pipefail ensures that status codes from Cosign aren&rsquo;t masked when piped to jq. Learn more To get up to speed with Sigstore, you can review the Sigstore section of Chainguard Academy, visit the upstream Sigstore Docs site, and check out the Sigstore organization on GitHub. You can learn more about verifying software artifacts with Cosign by reading How to Verify File Signatures with Cosign.
Navigate to our container images landing page or Getting Started Guides to understand more about Chainguard Containers and how they offer low-to-zero CVEs.

