Using signed provenance and Binary Authorization

This page provides instructions on how you can view build provenance metadata and control deployments with Cloud Build.

Build provenance is a collection of verifiable data about a build run by Cloud Build. Provenance metadata includes details such as the digests of the built images, the input source locations, the build arguments, and the build duration.

To help you secure your software supply chain, Cloud Build records provenance metadata and creates attestations for container images at build time. You can use the provenance metadata for auditing purposes and use the attestations to control deployments with Binary Authorization.

Limitations

Cloud Build generates all Binary Authorization and Container Analysis resources in the same project. If you run your deployment platform in another project, when configuring Binary Authorization, then you must refer to the Cloud Build project when adding the built-by-cloud-build attestor.

Before you begin

  • To view the generated metadata about build provenance:

    Enable the Cloud Build, Container Analysis, and Artifact Registry APIs.

    Enable the APIs

  • To control deployments with Binary Authorization and view the attestor metadata:

    1. Enable the Cloud Build, Binary Authorization, and Artifact Registry APIs.

      Enable the APIs

    2. Set up Binary Authorization for your platform.

View build provenance

This section explains how to view the build provenance metadata created by Cloud Build.

When you build an image with Cloud Build, the image's build provenance is automatically recorded. You can later fetch this information for auditing purposes. To generate the provenance metadata, run a build with Cloud Build.

To view the provenance metadata, run the following command:

gcloud artifacts docker images describe \
LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH \
--show-provenance

Replace the placeholder values in the command with the following:

  • LOCATION: Regional or multi-regional location.
  • PROJECT_ID: Google Cloud project ID.
  • REPOSITORY: Name of the repository
  • IMAGE: Image's name.
  • HASH: The sha256 hash value of the image. You can find this in the output of your build.

The output is the container provenance, as described in the SLSA provenance spec. For example:

image_summary:
  digest: sha256:991ff3a4548c72e671070be2e86ff684fd0924f6b75ee60d25d85c8cdfde1293
  fully_qualified_digest: us-east1-docker.pkg.dev/PROJECT_ID/my-repo/my-image@sha256:991ff3a4548c72e671070be2e86ff684fd0924f6b75ee60d25d85c8cdfde1293
  registry: us-east1-docker.pkg.dev
  repository: my-repo
provenance_summary:
  provenance:
  - createTime: '2021-09-24T16:20:36.854156Z'
    dsseAttestation:
      envelope:
        payload: eyJfdHlwZS...
        payloadType: application/vnd.in-toto+json
        signatures:
        - keyid: projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1
          sig: MEQCIHusA75t6LoyCngZ1_ACc-wWOlTThW6VKCyz75bnmSU0AiBYV50eFWQlDlp2cF-OV1u6j1_CtmrFdCNJCdyB6pYFsw==
      statement:
        predicateType: https://slsa.dev/provenance/v0.1
        provenance:
          builderConfig:
            id: https://cloudbuild.googleapis.com/Worker@v336731714
          metadata:
            buildFinishedOn: '2021-09-24T16:20:35.828284Z'
            buildInvocationId: c2f645df-f705-4aab-8d8f-ba2b1260f8ab
            buildStartedOn: '2021-09-24T16:20:23.224165401Z'
          recipe:
            arguments:
            - '@type': type.googleapis.com/google.devtools.cloudbuild.v1.BuildStep
              args:
              - build
              - --network
              - cloudbuild
              - --no-cache
              - -t
              - us-east1-docker.pkg.dev/PROJECT_ID/my-repo/my-image:tag1
              ....

If want to verify that the metadata has not been tampered with, you can validate the provenance by performing the following steps:

  1. Create a new directory and go to that directory.

    mkdir provenance && cd provenance
    
  2. Using the information from the keyid field, get the public key.

    gcloud kms keys versions get-public-key 1 --location global --keyring attestor \
    --key builtByGCB --project verified-builder --output-file my-key.pub
    
  3. The payload contains the JSON representation of the provenance, encoded in base64url. Decode the data and store it in a file.

    gcloud artifacts docker images describe \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
    --format=json | jq -r '.provenance_summary.provenance[0].dsseAttestation.envelope.payload' | tr '\-_' '+/' | base64 -d > provenance.json
    
  4. The envelope also contains the signature over the provenance. Decode the data and store it in a file.

    gcloud artifacts docker images describe LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
    --format=json | jq -r '.provenance_summary.provenance[0].dsseAttestation.envelope.signatures[0].sig' | tr '\-_' '+/' | base64 -d > signature.bin
    
  5. Validate the signature.

    openssl dgst -sha256 -verify my-key.pub -signature signature.bin provenance.json
    

    After a successful validation, the output is Verified OK.

Require that your images have associated provenance metadata

If Cloud Build does not generate provenance metadata, the build is still completed successfully. To overwrite the default behavior and fail builds if Cloud Build does not generate provenance metadata for your image, add the requestedVerifyOption: VERIFIED option to your cloudbild.yaml file:

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: [ 'build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/quickstart-docker-repo/quickstart-image:tag1', '.' ]
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/quickstart-docker-repo/quickstart-image:tag1'
options:
  requestedVerifyOption: VERIFIED

After adding the requestedVerifyOption, Cloud Build only marks the build as successful if it can generate the corresponding provenance metadata. This also affects images built in a private pool, enabling provenance metadata and attestation generation for those images.

Control deployments with Binary Authorization

A policy in Binary Authorization is a set of rules that govern the deployment of images. You can configure a rule to require digitally signed attestations.

Cloud Build generates and signs attestations at build time. With Binary Authorization you can use the built-by-cloud-build attestor to verify the attestations and only deploy images built by Cloud Build. The built-by-cloud-build attestor is created the first time you run a build in a project.

To allow only images built by Cloud Build to be deployed, perform the following steps:

Console

  1. Go to the Binary Authorization page in the Google Cloud Console.

    Go to Binary Authorization.

  2. In the Policy tab, click Edit Policy.

  3. In the Edit Policy dialog, select Allow only images that have been approved by all of the following attestors.

  4. Click Add Attestors.

  5. In the Add attestors dialog box, do the following:

    1. Select Add by project and attestor name and perform the following steps:
      1. In the Project name field, enter the project where you run Cloud Build.
      2. Click the Attestor name field and note that the built-by-cloud-build attestor is available.
      3. Click built-by-cloud-build.
    2. Alternatively, select Add by attestor resource ID. In Attestor resource ID, enter projects/PROJECT_ID/attestors/built-by-cloud-build, replacing PROJECT_ID with the project where you run Cloud Build.
  6. Click Add 1 attestor.

  7. Click Save Policy.

gcloud

  1. Export your existing policy to a file using the following command:

    gcloud container binauthz policy export > /tmp/policy.yaml
    
  2. Edit your policy file.

  3. Edit one of the following rules:

    • defaultAdmissionRule
    • clusterAdmissionRules
    • istioServiceIdentityAdmissionRules
    • kubernetesServiceAccountAdmissionRules
  4. Add a requireAttestationsBy block to the rule if there isn't one there already.

  5. In the requireAttestationsBy block, add projects/<var>PROJECT_ID</var>/attestors/built-by-cloud-build, replacing PROJECT_ID with the project where you run Cloud Build.

  6. Save the policy file.

  7. Import the policy file.

    gcloud container binauthz policy import /tmp/policy.yaml
    

    The following is an example policy file that contains the reference to the built-by-cloud-build-attestor:

    defaultAdmissionRule:
      evaluationMode: REQUIRE_ATTESTATION
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
      requireAttestationsBy:
        - projects/PROJECT_ID/attestors/built-by-cloud-build
    name: projects/PROJECT_ID/policy
    

    Replace PROJECT_ID with the project ID where you run Cloud Build.

You can view policy errors in the Binary Authorization log messages for GKE or Cloud Run

Using dry-run mode

In dry-run mode, Binary Authorization checks policy compliance without actually blocking the deployment. Instead, policy compliance status messages are logged to Cloud Logging. You can use these logs to determine if your blocking policy is working correctly and to identify false positives.

To enable dry run, do the following:

Console

  1. Go to the Binary Authorization page in the Google Cloud Console.

    Go to Binary Authorization.

  2. Click Edit Policy.

  3. In Default Rule or a specific rule, select Dry-run mode.

  4. Click Save Policy.

gcloud

  1. Export the Binary Authorization policy to a YAML file:

    gcloud container binauthz policy export  > /tmp/policy.yaml
    
  2. In a text editor, set enforcementMode to DRYRUN_AUDIT_LOG_ONLY and save the file.

  3. To update the policy, import the file by executing the following command:

    gcloud container binauthz policy import /tmp/policy.yaml
    

You can view policy errors in the Binary Authorization log messages for GKE or Cloud Run

View attestor metadata

An attestor is created the first time you run a build in a project. The attestor id is projects/PROJECT_ID/attestors/built-by-cloud-build. You can check the build attestor metadata using the following command:

curl -X GET -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    https://binaryauthorization.googleapis.com/v1beta1/projects/PROJECT_ID/attestors/built-by-cloud-build

Replace PROJECT_ID with the project where you run Cloud Build.

The output contains information about the attestor and the corresponding public keys. For example:

name": "projects/PROJECT_ID/attestors/built-by-cloud-build",
  "userOwnedDrydockNote": {
    "noteReference": "projects/PROJECT_ID/notes/built-by-cloud-build",
    "publicKeys": [
      {
        "id": "//cloudkms.googleapis.com/v1/projects/verified-builder/locations/asia/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1",
        "pkixPublicKey": {
          "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMMvFxZLgIiWOLIXsaTkjTmOKcaK7\neIZrgpWHpHziTFGg8qyEI4S8O2/2wh1Eru7+sj0Sh1QxytN/KE5j3mTvYA==\n-----END PUBLIC KEY-----\n",
          "signatureAlgorithm": "ECDSA_P256_SHA256"
        }
      },
...
      }
    ],
    "delegationServiceAccountEmail": "service-942118413832@gcp-binaryauthorization.iam.gserviceaccount.com"
  },
  "updateTime": "2021-09-24T15:26:44.808914Z",
  "description": "Attestor autogenerated by build ID fab07092-30f4-4f70-caf7-4545cbc404d6"

What's next