Getting Started

This guide helps new users quickly set up Tekton Chains to secure their CI/CD pipelines by generating and verifying cryptographic signatures for Tekton TaskRuns.

TOC

Introduction

Use Cases

Tekton Chains helps you secure your software supply chain by automatically generating cryptographic signatures for your build artifacts. This guide demonstrates how to set up Tekton Chains, generate a signing key, run a simple task, and verify its signature.

Estimated Reading Time

10-15 minutes

Important Notes

  • Tekton Chains is installed by default in the tekton-pipelines namespace when using Alauda Devops Pipelines Operator
  • The signing keys should be securely managed; in production environments, consider using a key management system (KMS)
  • This guide uses the simplest configuration for demonstration purposes

Prerequisites

  • A Kubernetes cluster with Tekton Pipelines and Tekton Chains installed
  • kubectl CLI installed and configured to access your cluster
  • cosign CLI tool installed
  • jq CLI tool installed

Process Overview

StepOperationDescription
1Generate signing keysCreate a key pair for signing artifacts
2Configure Tekton ChainsSet up Chains to use the Tekton storage backend
3Run a sample taskCreate and run a simple TaskRun
4Verify the signatureExtract and verify the signature of the TaskRun

Step-by-Step Instructions

Step 1: Generate Signing Keys

For more details, please refer to Signing Key Configuration

Tekton Chains uses cryptographic keys to sign artifacts. By default, it looks for a secret named signing-secrets in the Chains namespace.

  1. Install cosign if you haven't already

  2. Generate a key pair and store it as a Kubernetes secret:

    $ COSIGN_PASSWORD={password} cosign generate-key-pair k8s://tekton-pipelines/signing-secrets
    
    Successfully created secret signing-secrets in namespace tekton-pipelines
    Public key written to cosign.pub
    TIP

    This password will be stored in a Kubernetes secret named signing-secrets in the tekton-pipelines namespace.

  3. Verify the secret was created:

    $ kubectl get secret signing-secrets -n tekton-pipelines
    
    NAME              TYPE     DATA   AGE
    signing-secrets   Opaque   3      3m

Step 2: Configure Tekton Chains

Configure Tekton Chains to store artifacts in Tekton format by applying the following configuration:

$ kubectl patch tektonconfigs.operator.tekton.dev config --type=merge -p='{
  "spec": {
    "chain": {
      "artifacts.oci.storage": "",
      "artifacts.taskrun.format": "in-toto",
      "artifacts.taskrun.storage": "tekton"
    }
  }
}'

Explanation of YAML fields:

  • artifacts.oci.storage: The storage type for OCI artifacts. Set to an empty string to skip store.
  • artifacts.taskrun.format: The format of the taskrun artifact. Set to in-toto to use in-toto format.
  • artifacts.taskrun.storage: The storage type for taskrun artifacts. Set to tekton to store in Tekton TaskRun annotations.

Step 3: Run a Sample Task

Now let's create a simple TaskRun that Chains will automatically sign.

  1. Create a simple TaskRun:

    $ export NAMESPACE=default
    
    $ cat <<'EOF' | kubectl create -n $NAMESPACE -f -
    apiVersion: tekton.dev/v1
    kind: TaskRun
    metadata:
      name: build-push-run-output-image-test
    spec:
      serviceAccountName: ""
      taskSpec:
        results:
        - name: IMAGE_URL
          type: string
        - name: IMAGE_DIGEST
          type: string
        steps:
        - name: create-image
          image: <registry>/ops/busybox:latest
          script: |-
            #!/bin/sh
            echo 'gcr.io/foo/bar' | tee $(results.IMAGE_URL.path)
            echo 'sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5' | tee $(results.IMAGE_DIGEST.path)
    EOF
    TIP

    Please replace the image <registry>/ops/busybox:latest with the actual image you want to use.

  2. Wait for the TaskRun to complete:

    $ kubectl get taskruns.tekton.dev -n $NAMESPACE -w
    
    NAME                               SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
    build-push-run-output-image-test   True        Succeeded   42s         33s

    Wait until the status shows Succeeded.

Step 4: Verify the Signature

Once the TaskRun completes, Tekton Chains will automatically sign it. Let's verify the signature.

  1. Get the TaskRun UID:

    export TASKRUN_UID=$(kubectl get taskruns.tekton.dev -n $NAMESPACE build-push-run-output-image-test -o jsonpath='{.metadata.uid}')
  2. Extract the signature:

    kubectl get taskruns.tekton.dev -n $NAMESPACE -o jsonpath="{.items[0].metadata.annotations.chains\.tekton\.dev/signature-taskrun-$TASKRUN_UID}" | base64 -d > sig
  3. Extract the payload using jq:

    cat sig | jq '.payload | @base64d' | jq -r '.' | jq '.'
Signature Payload
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "subject": [
    {
      "name": "gcr.io/foo/bar",
      "digest": {
        "sha256": "05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5"
      }
    }
  ],
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "predicate": {
    "buildConfig": {
      "steps": [
        {
          "annotations": null,
          "arguments": null,
          "entryPoint": "#!/bin/sh\necho 'gcr.io/foo/bar' | tee /tekton/results/IMAGE_URL\necho 'sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5' | tee /tekton/results/IMAGE_DIGEST",
          "environment": {
            "container": "create-image",
            "image": "oci://<registry>/ops/busybox@sha256:ce57c394018ade463dede7cbc721c41d7bc6bc858c62d810681ff41d00d8e942"
          }
        }
      ]
    },
    "buildType": "tekton.dev/v1beta1/TaskRun",
    "builder": {
      "id": "https://tekton.dev/chains/v2"
    },
    "invocation": {
      "configSource": {},
      "environment": {
        "annotations": {
          "cpaas.io/creator": "kubernetes-admin",
          "cpaas.io/updated-at": "2025-06-15T15:18:32Z",
          "pipeline.tekton.dev/release": "002f74eea37b0f5dbcfed39c13d7cd762c8fcdc4"
        },
        "labels": {
          "app.kubernetes.io/managed-by": "tekton-pipelines"
        }
      },
      "parameters": {}
    },
    "materials": [
      {
        "digest": {
          "sha256": "ce57c394018ade463dede7cbc721c41d7bc6bc858c62d810681ff41d00d8e942"
        },
        "uri": "oci://<registry>/ops/busybox"
      }
    ],
    "metadata": {
      "buildFinishedOn": "2025-06-15T15:18:41Z",
      "buildStartedOn": "2025-06-15T15:18:32Z",
      "completeness": {
        "environment": false,
        "materials": false,
        "parameters": false
      },
      "reproducible": false
    }
  }
}
  1. Verify the signature using cosign:

    $ cosign verify-blob-attestation --insecure-ignore-tlog --key k8s://tekton-pipelines/signing-secrets --signature sig --type slsaprovenance --check-claims=false /dev/null
    
    WARNING: Skipping tlog verification is an insecure practice that lacks transparency and auditability verification for the blob attestation.
    Verified OK

    If successful, you'll see Verified OK.

Expected Results

After completing this guide:

  • You have a working Tekton Chains setup with a signing key
  • Your TaskRuns are automatically signed when they complete
  • You can verify the signatures to ensure the integrity of your builds

This demonstrates the basic functionality of Tekton Chains. In a real-world scenario, you would:

  1. Configure Chains to sign container images and store signatures in your registry
  2. Set up a verification step in your deployment process
  3. Potentially use a cloud KMS for more secure key management

References