Tekton Chains
Supply Chain Security in Tekton Pipelines
Getting Started
Tekton Chains is currently experimental, and does not have any published releases.
To use Tekton Chains, you'll have to build and deploy your own release from git.
Installation
See DEVELOPMENT.md for a guide on how to build and deploy your own version.
Configuration
Chains uses a ConfigMap called chains-config in the tekton-chains namespace for configuration.
Supported keys include (scroll right for defaults):
| Key |
Description |
Supported Values |
Default |
artifacts.taskrun.format |
The format to store TaskRun payloads in. |
tekton |
tekton |
artifacts.taskrun.storage |
The storage backend to store TaskRun signatures in. |
tekton, oci, gcs, docdb |
tekton |
artifacts.taskrun.signer |
The signature backend to sign Taskrun payloads with. |
pgp, x509, kms |
x509 |
artifacts.oci.format |
The format to store OCI payloads in. |
tekton, simplesigning |
simplesigning |
artifacts.oci.storage |
The storage backend to store OCI signatures in. |
tekton, oci, gcs, docdb |
oci |
artifacts.oci.signer |
The signature backend to sign OCI payloads with. |
pgp, x509, kms |
x509 |
signers.kms.kmsref |
The URI reference to a KMS service to use in KMS signers. |
gcpkms://projects/<project>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key> |
|
storage.docdb.url |
The go-cloud URI reference to a docstore collection |
firestore://projects/<project>/databases/(default)/documents/<collection>?name_field=name |
|
Overview
Chains works by observing TaskRun executions, capturing relevant information, and storing it in a cryptographically-signed format.
TaskRuns can indicate inputs and outputs which are then captured and surfaced in the Chains payload formats, where relevant.
Chains uses the standard mechanisms (Results and PipelineResouces) where possible, and provides a few other mechanisms to hint at the correct inputs and outputs. These are outlined below:
Chains Type Hinting
When outputing an OCI image without using a PipelineResource, Chains will look for the following Results:
IMAGE_URL - The URL to the built OCI image
IMAGE_DIGEST - The Digest of the built OCI image
Note that these are provided automatically when using PipelineResources.
Signing Secrets
To get started signing things with Chains, you first have to instruct Chains on how to sign things.
Chains supports a few different signature schemes, including PGP/GPG, x509 and KMS systems.
The private key material (or access to it) is required by Chains in order to create signatures.
This section explains how to configure this for each type.
GPG/PGP
Chains expects the private key and passphrase to be in a secret called signing-secrets with the following structure:
- pgp.private-key (the private key)
- pgp.passphrase (the optional passphrase)
You can set all of these as fields in the Kubernetes secret signing-secrets:
kubectl create secret generic signing-secrets -n tekton-chains --from-file=pgp.passphrase --from-file=pgp.private-key --from-file=pgp.public-key
Setup
You'll need to create or upload an existing private key as Kubernetes secret.
If you don't have one already, but you can usually use something like this:
gpg --gen-key
Enter a passprase (make sure you remember it!) and a name for the key.
Next, you'll need to upload the private key as a Kubernetes Secret so Tekton can use it
to sign payloads.
To do that, export the public and private keys as files:
gpg --export-secret-key --armor $keyname > pgp.private-key
gpg --export --armor $keyname > pgp.public-key
And save the passphrase (if you set one) in it's own file:
echo -n $passphrase > pgp.passphrase
x509
Chains expects the private key to be stored as an unencrpyted PKCS8 PEM file (BEGIN PRIVATE KEY).
Chains only supports ed25519 and ecdsa keys today.
The private key is expected to be stored in a secret named signing-secrets under the key x509.pem.
Chains also supports keys generated by cosign, stored as an encrypted PEM file (ENCRYPTED COSIGN PRIVATE KEY).
To use a cosign generated key, chains will expect the following to be stored in a secret named signing-secrets:
cosign.key: the cosign-generated private key
cosign.password the password to decrypt the private key
Setup
To create an ecdsa keypair, you can do something like:
openssl ecparam -genkey -name prime256v1 > ec_private.pem
openssl pkcs8 -topk8 -in ec_private.pem -nocrypt
You can add this to the secret with something like:
kubectl create secret generic signing-secrets -n tekton-chains --from-file=x509.pem
Cosign
To create a cosign keypair, cosign.key and cosign.pub, install cosign and run the following:
cosign generate-key-pair
Cosign will prompt you for a password; store this password in a file called cosign.password.
You can create a secret with:
kubectl create secret generic signing-secrets -n tekton-chains --from-file=cosign.key --from-file cosign.password
KMS
Chains uses a "go-cloud" URI like scheme to refer to KMS references.
Chains supports GCP KMS and Hashicorp Vault today, but we would love to add support for more.
You can configure Chains to use a specific KMS key using the signers.kms.kmsref config key in chains-config.
For GCP, this should have the structure of gcpkms://projects/<project>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key>
where , , and are filled in appropriately.
For Vault, this should have the structure of hashivault://<keyname>, where the keyname is filled out appropriately.
The chains-controller deployment must have access to this somehow.
For GCP/GKE, we suggest using Workload Identity.
Other Service Account techniques would work as well.
NOTE
If your signing secrets is already populated, you may get the following error:
Error from server (AlreadyExists): secrets "signing-secrets" already exists
Simply prepend a delete:
kubectl delete secret signing-secrets -n tekton-chains && kubectl create secret generic signing-secrets -n tekton-chains --from-file=pgp.passphrase --from-file=pgp.private-key --from-file=pgp.public-key
Usage
In its default mode of operation, Chains works by observing all TaskRuns in your cluster.
When TaskRuns complete, Chains takes a snapshot of them.
Chains then converts this snapshot to one or more standard payload formats, signs them and stores them somewhere.
To try it out, create a TaskRun of your choice.
For a sample one, try this:
$ kubectl create -f examples/task-output-image.yaml
taskrun.tekton.dev/build-push-run-output-image-abcd created
Then, take the name of the TaskRun you just created, and wait for it to finish (SUCCEEEDED should be True).
$ kubectl get taskrun.tekton.dev/taskrun home-is-set-rwhzs
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
home-is-set-rwhzs True Succeeded 105s 100s
Next, retrieve the signature and payload from the object (they are stored as base64-encoded annotations):
$ kubectl get taskrun home-is-set-rwhzs -o=json | jq -r '.metadata.annotations["chains.tekton.dev/payload-taskrun"]' | base64 --decode > payload
$ kubectl get taskrun home-is-set-rwhzs -o=json | jq -r '.metadata.annotations["chains.tekton.dev/signature-taskrun"]' | base64 --decode > signature
Finally, we can check the signature:
gpg --verify signature payload
gpg: Signature made Mon Jul 27 14:42:01 2020 CDT
gpg: using RSA key 4FCFD41D993B806C
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 4 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 4u
gpg: next trustdb check due at 2022-03-16
gpg: Good signature from "Tekton Unit Tests <testing@tekton.dev>" [ultimate]
Now we have a verifiable record of the TaskRuns!
Want to contribute
We are so excited to have you!
See CONTRIBUTING.md for an overview of our processes
See DEVELOPMENT.md for how to get started
See ROADMAP.md for the current roadmap
Look at our good first issues and our help wanted issues