A complete guide to image signing with Tekton Chains on OCP — covering the concept, the setup, the pipeline integration, and verification.—

What Tekton Chains does
Tekton Chains works by reconciling the run of a task or a pipeline. Once the run is observed as completed, Tekton Chains takes a snapshot of the completed TaskRun/PipelineRun, and starts its core work in the order of: formatting (generate provenance JSON) → signing (sign the payload using the configured key) → uploading (upload the provenance and its signature to the configured storage).
It operates entirely automatically — you don’t modify your pipeline at all. Chains watches completed runs and signs in the background.
Step 1 — Chains is already installed on OCP
The Red Hat OpenShift Pipelines Operator installs Tekton Chains by default. You can configure Tekton Chains by modifying the TektonConfig custom resource; the Operator automatically applies the changes that you make.
# Verify Chains is runningoc get pods -n openshift-pipelines | grep chains# tekton-chains-controller-xxx Running
Step 2 — Generate a signing key pair
# Install cosign (if not already)brew install cosign # or download binary# Generate key pair — stores private key as K8s secret automaticallycosign generate-key-pair k8s://openshift-pipelines/signing-secrets# This creates:# signing-secrets (K8s Secret) — holds cosign.key + cosign.password# cosign.pub (local file) — distribute this for verification# Extract public key for distribution/verificationoc get secret signing-secrets -n openshift-pipelines \ -o jsonpath='{.data.cosign\.pub}' | base64 -d > cosign.pub
For production, use a KMS (AWS KMS, HashiCorp Vault, GCP KMS) instead of a file-based key:
# AWS KMS examplecosign generate-key-pair --kms awskms:///arn:aws:kms:ca-central-1:123456:key/abc-def
Step 3 — Configure Chains via TektonConfig
Cluster administrators can use Tekton Chains to sign and verify images and provenances by: creating an encrypted x509 key pair and saving it as a Kubernetes secret; setting up authentication for the OCI registry to store images, image signatures, and signed image attestations; and configuring Tekton Chains to generate and sign provenance.
apiVersion: operator.tekton.dev/v1alpha1kind: TektonConfigmetadata: name: configspec: chain: # Format for TaskRun attestations artifacts.taskrun.format: "slsa/v1" # SLSA v1.0 provenance artifacts.taskrun.storage: "oci" # store in OCI registry # Format for PipelineRun attestations (recommended) artifacts.pipelinerun.format: "slsa/v1" artifacts.pipelinerun.storage: "oci" artifacts.pipelinerun.enable-deep-inspection: "true" # inspect child TaskRuns # OCI image signature format artifacts.oci.format: "simplesigning" artifacts.oci.storage: "oci" # Transparency log (Sigstore Rekor) transparency.enabled: "true" transparency.url: "https://rekor.sigstore.dev" # or your internal Rekor # Signing key reference signers.cosign.key: "k8s://openshift-pipelines/signing-secrets"
Apply via oc patch if you prefer:
oc patch tektonconfig config --type=merge -p='{ "spec": { "chain": { "artifacts.pipelinerun.format": "slsa/v1", "artifacts.pipelinerun.storage": "oci", "artifacts.oci.format": "simplesigning", "artifacts.oci.storage": "oci", "transparency.enabled": "true" } }}'
Step 4 — Type-hint your pipeline so Chains knows what to sign
Chains discovers what the output artifact is via type hints in Task results. Your build task must emit IMAGE_URL and IMAGE_DIGEST results:
apiVersion: tekton.dev/v1kind: Taskmetadata: name: buildah-pushspec: params: - name: IMAGE type: string results: # Type hints — Chains reads these to find the artifact - name: IMAGE_URL description: The image URL - name: IMAGE_DIGEST description: The image digest (sha256) steps: - name: build-and-push image: registry.redhat.io/rhel8/buildah script: | buildah bud -t $(params.IMAGE) . buildah push $(params.IMAGE) \ --digestfile /tmp/digest # Emit type hints for Chains echo -n "$(params.IMAGE)" | tee $(results.IMAGE_URL.path) cat /tmp/digest | tee $(results.IMAGE_DIGEST.path)
For pipeline-level provenance, also emit results at the Pipeline level:
apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: ci-pipelinespec: results: - name: IMAGE_URL value: $(tasks.build.results.IMAGE_URL) - name: IMAGE_DIGEST value: $(tasks.build.results.IMAGE_DIGEST) tasks: - name: build taskRef: name: buildah-push
Step 5 — What happens automatically after a run
Once your PipelineRun completes, Chains fires automatically. You can watch for the signed annotation:
# Watch for Chains to finish signingoc get pipelinerun my-run -o json | jq '.metadata.annotations'# {# "chains.tekton.dev/signed": "true",# "chains.tekton.dev/transparency": "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=12345678"# }# What gets stored in the OCI registry alongside your image:# myimage:sha256-abc123.sig ← cosign image signature# myimage:sha256-abc123.att ← SLSA provenance attestation
Step 6 — Verify images before deployment
# Set your image reference (always use digest, not tag)IMAGE="quay.io/my-org/my-app@sha256:abc123..."# 1. Verify the image signaturecosign verify \ --key cosign.pub \ $IMAGE# 2. Verify the SLSA provenance attestationcosign verify-attestation \ --key cosign.pub \ --type slsaprovenance \ $IMAGE | jq '.payload | @base64d | fromjson'# 3. Check the Rekor transparency log entryrekor-cli search --sha sha256:abc123...
The SLSA provenance JSON tells you exactly what built the image — the git commit, the pipeline name, each task step, and all input dependencies.
Step 7 — Enforce signatures at admission (policy gate)
Verification at deployment time is where this pays off. Use OCP’s built-in image policy or Kyverno/OPA to block unsigned images:
# Kyverno policy — block any image without a valid Chains signatureapiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-signed-imagesspec: validationFailureAction: Enforce rules: - name: check-image-signature match: resources: kinds: [Pod] verifyImages: - imageReferences: - "quay.io/my-org/*" attestors: - entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- <your cosign.pub contents> -----END PUBLIC KEY----- attestations: - predicateType: https://slsa.dev/provenance/v1 conditions: - all: - key: "{{ builder.id }}" operator: Equals value: "https://tekton.dev/chains/v2"
SLSA levels Tekton Chains achieves
| SLSA level | Requirement | Chains status |
|---|---|---|
| Level 1 | Provenance exists | Achieved — attestation generated automatically |
| Level 2 | Signed provenance, hosted build | Achieved — cosign signature + Rekor log entry |
| Level 3 | Hardened build platform, non-falsifiable provenance | Achieved with OCP’s isolated pod builds |
| Level 4 | Two-party review, hermetic builds | Partial — requires additional hermetic build config |
The key benefit: by implementing provenance in CI/CD pipelines, you protect your supply chain from tampering and unauthorized access, streamline compliance with evolving industry and government regulations, and enhance visibility and trust throughout your software lifecycle.