# Verifying Chainguard Containers and metadata signatures with Cosign

URL: https://chainguard-docs-preview-git-1016-404s.chainguard.app/chainguard/containers/security-and-compliance/verifying-chainguard-images-and-metadata-signatures-with-cosign.md
Last Modified: October 8, 2026
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'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](/open-source/sigstore/cosign/how-to-install-cosign/) and [jq](https://stedolan.github.io/jq/) to be installed on your machine to download and verify image attestations.

## Registry and tags for Chainguard Containers

Attestations are provided per image build, so you'll need to specify the correct tag and registry when pulling attestations from an image with `cosign`. This guide works with Chainguard's public and private registries:

- `cgr.dev/chainguard`: The public registry contains Chainguard's **Free container images**, which only include the `:latest` versions of an image.
- `cgr.dev/YOUR-ORGANIZATION`: A private/dedicated registry contains your organization'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 default to the `:latest` tag, but you can specify a different tag to fetch attestations for.

## Chainguard'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 `image-syncer` identity is used to sign images that have been imported directly from the Chainguard Containers catalog.
- The `custom-image-builder` identity is used to sign any images that have been customized for your organization, such as those built with [Custom Assembly](/chainguard/containers/custom-assembly/overview/).

> **Note**: Older Chainguard organizations use `catalog_syncer` and `apko_builder` instead of these identities. Each pair is functionally identical, because each references the same account association: `image-syncer` and `catalog_syncer` both reference the `CATALOG_SYNCER` association, while `custom-image-builder` and `apko_builder` both reference the `APKO_BUILDER` association.


These identities are created and added to every [verified Chainguard organization](/platform/administration/iam-organizations/verified-orgs/) automatically.

To follow along with the **Private Registry** examples in this guide, you 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:

```shell
PARENT=your-organization
```

Next, create two more variables to hold the UIDPs of your organization's `image-syncer` and `custom-image-builder` identities (`catalog_syncer` and `apko_builder` for older organizations), respectively:

```shell
IMAGE_SYNCER=$(chainctl iam account-associations describe $PARENT -o json | jq -r '.[].chainguard.service_bindings.CATALOG_SYNCER')
CUSTOM_IMAGE_BUILDER=$(chainctl iam account-associations describe $PARENT -o json | jq -r '.[].chainguard.service_bindings.APKO_BUILDER')
```

The **Private Registry** examples in this guide include these environment variables, letting you verify that Chainguard used those identities to sign the given image.

You can also find these values in the Chainguard Console. After logging in, go to **Settings**, and then **Users**. From there, scroll or search for either `image-syncer` or `custom-image-builder` (or `catalog_syncer` or `apko_builder` for older organizations) and click its row to find the identity's UIDP.

## Verifying container image signatures

Chainguard signs its containers with Sigstore, and you can check the included signatures using `cosign`. The `cosign verify` command pulls detailed information about all signatures found for the provided image.

### Public registry

```shell
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

```shell
IMAGE=go
cosign verify \
  --certificate-oidc-issuer=https://issuer.enforce.dev \
  --certificate-identity-regexp="https://issuer.enforce.dev/(${IMAGE_SYNCER}|${CUSTOM_IMAGE_BUILDER})" \
  cgr.dev/${PARENT}/${IMAGE} | jq
```

Be aware that you 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 fetches signatures for the `:latest` tag. If you'd like, you can specify the tag you want to fetch signatures for:

```shell
IMAGE=go
TAG=1.23.8
cosign verify \
  --certificate-oidc-issuer=https://issuer.enforce.dev \
  --certificate-identity-regexp="https://issuer.enforce.dev/(${IMAGE_SYNCER}|${CUSTOM_IMAGE_BUILDER})" \
  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](https://slsa.dev/attestation-model) for a container image can be obtained and verified using Cosign or directly in the Chainguard Console. Refer to [How to retrieve attestations and SBOMs for Chainguard Containers](/chainguard/containers/security-and-compliance/retrieve-image-sboms/) for more information.

### Public registry

```shell
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

```shell
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 container image attestations

You can use the `cosign verify-attestation` command to check the signatures of the desired container image [attestations](https://slsa.dev/attestation-model):

### Public registry

```shell
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} | jq
```

This pulls in the signature for the attestation specified by the `--type` parameter, which in this case is the SPDX attestation for SBOMs. The output verifies the SBOM attestation signature in Cosign's transparency log:

```shell
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

```shell
IMAGE=go
cosign verify-attestation \
  --type https://spdx.dev/Document \
  --certificate-oidc-issuer=https://issuer.enforce.dev \
  --certificate-identity-regexp="https://issuer.enforce.dev/(${IMAGE_SYNCER}|${CUSTOM_IMAGE_BUILDER})" \
  cgr.dev/${PARENT}/${IMAGE} | jq
```

## Air-gapped and egress-restricted environments

The commands in this guide reach the public Sigstore infrastructure to fetch the trust root Cosign verifies against. If that infrastructure is unreachable, you can export the trust root on a connected machine and pass it to Cosign as a file. Transparency-log verification still works, because the signature carries its own signed entry timestamp.

The signature is a separate artifact from the image, so mirroring the image alone leaves it behind. For the full procedure, including how to move signatures and attestations across an air gap, see [Verifying signatures in air-gapped environments](/open-source/sigstore/cosign/verifying-in-air-gapped-environments/).

## 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'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` overwrites 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't masked when piped to `jq`.

## Learn more

To get up to speed with Sigstore, you can review the [Sigstore](/open-source/sigstore/) section of Chainguard Academy, visit the upstream [Sigstore Docs](https://docs.sigstore.dev/) site, and check out the [Sigstore organization on GitHub](https://github.com/sigstore). You can learn more about verifying software artifacts with Cosign by reading [How to verify file signatures with Cosign](/open-source/sigstore/cosign/how-to-verify-file-signatures-with-cosign/).

Navigate to our [container images](/chainguard/containers/) landing page or [Getting started guides](https://edu.chainguard.dev/chainguard/containers/getting-started/) to understand more about Chainguard Containers and how its images offer low-to-zero CVEs.

