Using Cosign to verify Konflux build signatures & attestations

In this section we’ll provide examples showing how to use cosign to verify signatures and attestations for builds created by Konflux CI.

For detailed information on Cosign refer to the official documentation.

This document assumes cosign version 2.

Introduction

Konflux uses Tekton Chains to sign the images created by Konflux build pipelines, and to create signed attestations that include details about the Tekton pipeline run that created the image.

It’s possible to verify these signatures and view the attestation directly using cosign. This does require that you know the image ref of the container image that was created, (i.e. the container repository and a tag or digest), of the image that was created, and that you have access to that repository.

Obtain image reference

When validating an image, from an application component for example, it is recommended to always use an image reference includes a digest. The Konflux build pipelines emit results that contain this information. They are called IMAGE_URL and IMAGE_DIGEST. Combine the two with the @ to create the image reference with a digest. For example, if IMAGE_URL is quay.io/konflux-ci/user-workload, and IMAGE_DIGEST is sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d, the image reference that should be used during validatin is quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d.

It is also possible to obtain the image reference from the Web UI.

Obtain public key

Currently, Konflux uses a long-lived key for signing. This key can be retrieved from the corresponding member cluster:

kubectl get -n openshift-pipelines secret public-key -o json | jq -r '.data."cosign.pub" | @base64d' > cosign.pub

Validating the image

The first step in validating an image is verifying it has been signed with the proper signature. This is to ensure the image was indeed built in a Konflux build pipeline.

$ IMAGE='quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d'
$ cosign verify --key cosign.pub $IMAGE --insecure-ignore-tlog
WARNING: Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the signature.

Verification for quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key

[{"critical":{"identity":{"docker-reference":"quay.io/konflux-ci/user-workload"},"image":{"docker-manifest-digest":"sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d"},"type":"cosign container image signature"},"optional":null}]
At the moment, Konflux does not use a transparency log like Rekor. Starting with version 2, cosign requires the explicit flag --insecure-ignore-tlog to not use Rekor during the verification process.

Next, validate that the image contains the expected SLSA Provenance attestations. Images built by the Konflux build pipeline will have two of them. One representing the Tekton TaskRun in which the image was built, and one representing the Tekton PipelineRun that contains the previously mentioned TaskRun. The attestation for the PipelineRun is useful in understanding all the steps used when building the image.

$ IMAGE='quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d'
$ cosign verify-attestation --type slsaprovenance  --key cosign.pub $IMAGE --insecure-ignore-tlog > slsa-provenance-attestations.json
WARNING: Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the attestation.

Verification for quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key

The output of the cosign verify-attestation command displays the attestations themselves. The snippet above saves those attestations into a file, called slsa-provenance-attestations.json.

At this point, a policy engine like OPA or conftest can be used to validate the contents of the attestations.

At the moment, the Software Bill of Materials (SBOM) attachment is not signed. However, it can be inspected via the cosign download sbom command. It is important to note that this command offers no guarantee that the SBOM attachment was produced as part of the Konflux build pipeline.

$ IMAGE='quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d'
$ cosign download sbom $IMAGE > sbom.json
WARNING: Downloading SBOMs this way does not ensure its authenticity. If you want to ensure a tamper-proof SBOM, download it using 'cosign download attestation <image uri>' or verify its signature using 'cosign verify --key <key path> --attachment sbom <image uri>'.
Found SBOM of media type: application/vnd.cyclonedx+json

The snippet above saves the SBOM into a file named sbom.json. This file could also be used as input to a policy engine. However, beware that since it is not signed, it is susceptible to modifications outside the Konflux build pipeline.

Using cosign tree

cosign tree is a useful command that lists all related entities for an image, such as image signatures, image attestations, and Software Bill of Materials (SBOM) attachments.

For example:

$ IMAGE='quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d'
$ cosign tree $IMAGE
📦 Supply Chain Security Related artifacts for an image: quay.io/konflux-ci/user-workload@sha256:de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d
└── 💾 Attestations for an image tag: quay.io/konflux-ci/user-workload:sha256-de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d.att
   ├── 🍒 sha256:410f897e3649a8688a0ffbcbe7c370679d9a24ec31be0a433431e4110d335fb4
   ├── 🍒 sha256:7a8154760765d3ec8f27b1c40f55d5f1c3273edf268e38ba5a01c55bc98dac4d
   └── 🍒 sha256:3c487af472fcf00827acd8721156da0e39bd8ca2aa9437aa8c5dfdc6b725e9b9
└── 🔐 Signatures for an image tag: quay.io/konflux-ci/user-workload:sha256-de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d.sig
   └── 🍒 sha256:cce08e81cb1722dc91c80e80b72964f41841a8351da2c60ae090138dbbdff83d
└── 📦 SBOMs for an image tag: quay.io/konflux-ci/user-workload:sha256-de1c78cd8321ec999187dfc95ed5470b4a5b2bf5121a2482dba7b5965868253d.sbom
   └── 🍒 sha256:72f7c108f43c4594bec8459d516ec3e2e568474ae9fd0e974d5b1b70288238cc

Although cosign tree is not necessary for validation, it is a powerful command to inspect the current state of an image.