This topic tells you how to configure Tanzu Build Service to generate Supply-chain Levels for Software Artifacts (SLSA) attestations for image resources. It also describes how you can view the attestation and verify the signature.
Tanzu Build Service supports generating SLSA v1 attestations. Tanzu Build Service can achieve SLSA security levels up to L3
depending on how the installation and workload is configured. This section documents how Tanzu Build Service adheres to each SLSA security level.
For more technical details about how kpack handles SLSA, see the kpack documentation in GitHub.
Specification: Build L0: No guarantees
This is the default level in Tanzu Build Service because attestations are not generated unless configured for your installation.
Specification: Build L1: Provenance exists
This is the level Tanzu Build Service achieves if SLSA generation is enabled.
Specification: Build L2: Hosted build platform
This is the level Tanzu Build Service achieves if SLSA generation is enabled and a signing key is attached to the service account of the workload.
Specification: Build L3: Hardened builds
This is the level Tanzu Build Service achieves if SLSA generation is enabled and a signing key is attached to the service account of the workload.
Before you can configure Tanzu Build Service to sign your image builds, you must:
To view and verify signed attestations, install Cosign and jq. For instructions, see the Cosign documentation and jq documentation.
To view unsigned attestations, install Crane. For instructions, see the Crane documentation.
Ensure that you have access to the base64
and awk
commands. These commands are pre-installed on every macOS and Linux machine.
Have a Builder or ClusterBuilder resource configured. For instructions, see Manage builders for Tanzu Build Service.
Tanzu Build Service does not generate SLSA attestation by default. Enable this by setting generate_slsa_attestation: true
during installation.
If Tanzu Build Service has SLSA attestation enabled, every app image built by Tanzu Build Service generates a second image where the attestation is stored.
No action is required to configure the Image or Workload resources.
To view the attestation, run:
crane export ATTESTATION-TAG | jq --raw-output '.payload' | base64 --decode | jq
Where ATTESTATION-TAG
is the tag derived from the app image’s digest. For more information, see Location of the attestation later in this topic.
For more information about the attestation, see the kpack documentation.
For an example of expected output, see the kpack documentation
If the service account of the workload has a secret with a signing key attached, Tanzu Build Service automatically signs the generated attestation.
To generate and save the signing key:
Use the cosign CLI to generate the Kubernetes secret:
cosign generate-key-pair k8s://NAMESPACE/COSIGN-KEYPAIR-NAME
Where:
NAMESPACE
is the namespace to store the Kubernetes secret in.COSIGN-KEYPAIR-NAME
is the name of the Kubernetes secret.You will see a cosign.pub
file in your current directory. Keep this file as you need it to verify the signature of the images that are built.
Annotate the secret to use it for signing SLSA attestations by running:
kubectl annotate secret COSIGN-KEYPAIR-NAME 'kpack.io/slsa='
Tanzu Build Service only considers secrets with the annotation kpack.io/slsa: ""
for signing.
Attach the secret to the service account by running:
kubectl patch serviceaccount SERVICE-ACCOUNT-NAME -p '{"secrets":[{"name":"COSIGN-KEYPAIR-NAME"}]}'
Where SERVICE-ACCOUNT-NAME
is the name of the service account that the workload will use.
No action is required to configure the Image or Workload resource.
Because Cosign operates on the tag-based discovery, you can only view the latest attestation for a reproducible build. For more information, see Reproducible builds later in this topic.
To verify the signature of the attestation, run:
cosign verify-attestation \
--insecure-ignore-tlog=true \
--key PUBLIC-KEY \
--type=slsaprovenance1 APP-IMAGE-DIGEST > /dev/null
Where:
PUBLIC-KEY
is either k8s://NAMESPACE/COSIGN-KEYPAIR-NAME
from Generate and save the signing key earlier or the path to the cosign.pub
that was generated.APP-IMAGE-DIGEST
is digest of the image that the workload built.Example output:
Verification for index.docker.io/your-project/app@sha256:1234... --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
(Optional) To view the generated attestation, run:
cosign verify-attestation \
--insecure-ignore-tlog=true \
--key PUBLIC-KEY \
--type=slsaprovenance1 APP-IMAGE-DIGEST | jq \
--raw-output '.payload' | base64 --decode | jq
Where:
PUBLIC-KEY
is either k8s://NAMESPACE/COSIGN-KEYPAIR-NAME
from Generate and save the signing key earlier or the path to the cosign.pub
that was generated.APP-IMAGE-DIGEST
is the digest of the image that the workload built.For more information about the attestation, see the kpack documentation.
For an example of expected output, see the kpack documentation.
The tag of the attestation image is predictable from the digest of the app image.
If the digest of your app image is index.docker.io/your-project/app@sha256:1234
, the tag of your attestation image is index.docker.io/your-project/app:sha256-1234.att
.
Tanzu Build Service supports reproducible builds. This means that it’s possible for a build to generate the exact same bit-for-bit image as a previous run. This is most likely to occur if a build is manually re-triggered, but might also automatically occur as part of a dependency upgrade.
In these cases, because the image is bit-for-bit identical and has the same digest as the previous image, the tag of the attestation image overlaps. In this scenario, the newer attestation overwrites the older attestation.
To view the older attestation, the digest of the attestation image is exposed in the status of the Build resource under the key .status.latestAttestationImage
. You can retrieve this by running:
kubectl get builds.kpack.io BUILD-NAME -o yaml
Where BUILD-NAME
is the name of the Build resource. It is usually in the format IMAGE-NAME-build-N
.
Expected output:
apiVersion: kpack.io/v1alpha2
kind: Build
...
status:
...
latestAttestationImage: index.docker.io/your-project/app@sha256:1234