This tutorial will cover how to set up Chains to sign OCI images built in Tekton, and how to automatically generate and sign in-toto attestations for each image. This tutorial will also cover how to store these attestations in a transparency log and query the log for the attestation.
This tutorial will guide you through:
- Generating your own keypair and storing it as a Kubernetes Secret
- Setting up authentication for your OCI registry to store images, image signatures and signed image attestations
- Configuring Tekton Chains to generate and sign provenance
- Building an image with kaniko in a Tekton TaskRun
- Verifying the signed image and the signed provenance
A Kubernetes cluster with the following installed:
- Tekton Chains
- Tekton Pipelines
First, we'll generate an encrypted x509 keypair and save it as a Kubernetes secret. Install cosign and run the following:
cosign generate-key-pair k8s://tekton-chains/signing-secrets
cosign will prompt you for a password, which will be stored in a Kubernetes secret named signing-secrets
in the tekton-chains
namespace.
The public key will be written to a local file called cosign.pub
.
There are two forms of authentication that need to be set up:
- The Chains controller will be pushing signatures to an OCI registry using the credentials linked to your
TaskRun
's service account. See our authentication doc - The Kaniko Task that will build and push the image needs push permissions for your registry.
To set up auth for the Kaniko Task, you'll need a Kubernetes secret of a docker config.json
file which contains the required auth.
You can create the secret by running:
kubectl create secret generic [DOCKERCONFIG_SECRET_NAME] --from-file [PATH TO CONFIG.JSON]
You'll need to make these changes to the Tekton Chains Config:
artifacts.taskrun.format=slsa/v1
artifacts.taskrun.storage=oci
transparency.enabled=true
You can set these fields by running
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.format": "slsa/v1"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.storage": "oci"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"transparency.enabled": "true"}}'
Note, you can continue to use the older alias of slsa/v1
: in-toto
above.
This tells Chains to generate an in-toto attestation and store it in the specified OCI registry. Attestations will also be stored in rekor since transparency is enabled.
Great, now that the setup is done we're finally ready to build an image with kaniko!
First, apply the Kaniko Task to your cluster:
kubectl apply -f examples/kaniko/kaniko.yaml
and set the following environment variables:
REGISTRY=[The registry you'll be pushing to]
DOCKERCONFIG_SECRET_NAME=[The name of the secret with the docker config.json]
Then, you can start the Kaniko Task with the Tekton CLI tool, tkn:
tkn task start --param IMAGE=$REGISTRY/kaniko-chains --use-param-defaults --workspace name=source,emptyDir="" --workspace name=dockerconfig,secret=$DOCKERCONFIG_SECRET_NAME kaniko-chains
You can watch the logs of this Task until they complete; if authentication is set up correctly than the final image should be pushed to $REGISTRY/kaniko-chains
.
Once the TaskRun has successfully completed, you'll need to wait a few seconds for Chains to generate provenance and sign it.
Once you see the chains.tekton.dev/signed=true
annotation on your TaskRun you know that Chains has completed the signing process and you're ready to move on to verification:
kubectl get tr [TASKRUN_NAME] -o json | jq -r .metadata.annotations
{
"chains.tekton.dev/signed": "true",
...
}
To verify the image and the attestation, we'll use cosign
again:
cosign verify --key cosign.pub $REGISTRY/kaniko-chains
cosign verify-attestation --key cosign.pub --type slsaprovenance $REGISTRY/kaniko-chains
You should see verification output for both!
To find provenance for the image in Rekor, first get the digest of the $REGISTRY/kaniko-chains
image you just built.
You can look this up in the TaskRun, or pull the image to get the digest.
You can then search rekor to find all entries that match the sha256 digest of the image you just built with the rekor-cli tool:
rekor-cli search --sha [IMAGE_DIGEST]
[UUID1]
[UUID2]
The search will print out the UUIDs of matching entries. It may take a little guessing, but one of those UUIDs holds the attestation. You can see the attestation by using jq:
rekor-cli get --uuid [UUID] --format json | jq -r .Attestation | base64 --decode | jq
Congratulations! You have officially built an image, signed it, and generated signed provenance for it with Tekton Chains 🎉
This diagram shows what you just deployed: