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.

About SLSA security levels in Tanzu Build Service

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.

Build L0

Specification: Build L0: No guarantees

This is the default level in Tanzu Build Service because attestations are not generated unless configured for your installation.

Build L1

Specification: Build L1: Provenance exists

This is the level Tanzu Build Service achieves if SLSA generation is enabled.

  • The build process is consistent. You can see an example app with expected output in Create an image.
  • The provenance generated is complete, but it is unsigned.
  • To view the generated provenance, see View the attestation later in this topic.

Build L2

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.

  • All builds executed by Tanzu Build Service occur on a dedicated Kubernetes cluster, not the user’s workstation.
  • To verify the attestation signature, see Verify the attestation signature.

Build L3

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.

  • Builds are isolated from each other by using a different Kubernetes pod per build process.
  • Signing keys are only readable by Tanzu Build Service system resources. No user defined build steps, such as custom Buildpacks, custom Stacks, and custom Builders, can access the signing keys.
  • You can use Kubernetes Role-Based Access Control (RBAC) to secure the signing keys at the cluster level.

Prerequisites

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.

Enable SLSA attestation

Tanzu Build Service does not generate SLSA attestation by default. Enable this by setting generate_slsa_attestation: true during installation.

Create unsigned attestations (SLSA L0)

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.

Build the image

No action is required to configure the Image or Workload resources.

View the attestation

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

Create signed attestations (SLSA L3)

If the service account of the workload has a secret with a signing key attached, Tanzu Build Service automatically signs the generated attestation.

Generate and save the signing key

To generate and save the signing key:

  1. 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.

  2. 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.

  3. 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.

Build the image

No action is required to configure the Image or Workload resource.

Verify the attestation signature

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.

  1. 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
    
  2. (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.

Location of the attestation

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.

Reproducible builds

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
check-circle-line exclamation-circle-line close-line
Scroll to top icon