Viewing build provenance

This page provides instructions on how you can view build provenance metadata generated by Cloud Build.

Cloud Build supports the generation of build provenance that meets Supply-chain Levels for Software Artifacts (SLSA) level 2 assurance.

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.

Before you begin

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

    Enable the APIs

  2. To use the command-line examples in this guide, install and configure the Google Cloud SDK.

This feature only works with container images stored in Artifact Registry.

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.

  1. To generate the provenance metadata, run a build with Cloud Build.

    Push the built image using the images field instead of a docker push build step. Cloud Build only generates attestations for images pushed via the images field.

  2. To view the generated 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:370938421b670a1489b98adac2ad41709bf0892be36382d50d563868dbfa5b16
      fully_qualified_digest: us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH
      registry: us-central1-docker.pkg.dev
      repository: REPOSITORY
    provenance_summary:
      provenance:
      - build:
          intotoStatement:
            _type: https://in-toto.io/Statement/v0.1
            predicateType: https://slsa.dev/provenance/v0.1
            slsaProvenance:
              builder:
                id: https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2
              materials:
              - digest: 
                  md5: 6bbe6fa4c15b6486a03717bbf8b84f5c
                uri: https://github.com/user/repo/commit/1f25aed0a18e0bc674b6113f2d901306a3a9cb38
              metadata:
                buildFinishedOn: '2022-03-02T16:46:08.977469Z'
                buildInvocationId: 64def907-dbbd-4862-895a-0f67c95fcf2c
                buildStartedOn: '2022-03-02T16:45:55.972778547Z'
              recipe:
                arguments:
                  '@type': type.googleapis.com/google.devtools.cloudbuild.v1.Build
                  id: 64def907-dbbd-4862-895a-0f67c95fcf2c
                  options:
                    logging: LEGACY
                    pool: {}
                  sourceProvenance:
                    fileHashes:
                      gs://PROJECT_ID_cloudbuild/source/1646239554.496829-decf6ad639ea4470a569ff24c8f736f3.tgz#1646239555011921:
                        fileHash:
                        - type: MD5
                          value: 6vBB10o8CcNn1hUjzxjgcQ==
                    resolvedStorageSource:
                      bucket: PROJECT_ID_cloudbuild
                      generation: '1646239555011921'
                      object: source/1646239554.496829-decf6ad639ea4470a569ff24c8f736f3.tgz
                  steps:
                  - args:
                    - build
                    - --network
                    - cloudbuild
                    - --no-cache
                    - -t
                    - us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:tag1
                    - .
                    name: gcr.io/cloud-builders/docker
                    pullTiming:
                      endTime: '2022-03-02T16:46:01.718245526Z'
                      startTime: '2022-03-02T16:46:01.712281272Z'
                    status: SUCCESS
                    timing:
                      endTime: '2022-03-02T16:46:03.364690833Z'
                      startTime: '2022-03-02T16:46:01.712281272Z'
                type: https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2
            subject:
            - digest:
                sha256: 370938421b670a1489b98adac2ad41709bf0892be36382d50d563868dbfa5b16
              name: https://us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:tag1
        createTime: '2022-03-02T16:46:09.980577Z'
        envelope:
          payload: eyJfdHlwZSI...
          payloadType: application/vnd.in-toto+json
          signatures:
          - keyid: projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1
            sig: MEYCIQCX87CG-4qGHkHKQIT7Z5t0vdG1cPqStwUwNapm4YQBfQIhAMYLaiKG9nnzHIsVmxWesoOw-WF8knNE14aE-Goeh7X0
        kind: BUILD
        name: projects/PROJECT_ID/occurrences/0168ea5c-0b84-475e-b786-ea80bbab15d1
        noteName: projects/verified-builder/notes/intoto_64def907-dbbd-4862-895a-0f67c95fcf2c
        resourceUri: https://us-central1-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH
        updateTime: '2022-03-02T16:46:09.980577Z'
    

    Two important things to notice in this example:

    • The build was triggered from a GitHub repository. You can see the corresponding commit in the materials field.

    • The digest and fileHash fields refer to the same object. The digest field is encoded in base 16 (hex-encoded) and the fileHash field in base 64.

View build provenance for regional pools

Cloud Build does not generate provenance metadata for builds in regional pool, whether you are using a private-pool or a default pool with an assigned region. You can enable provenance metadata for regional builds by adding an option to your build file. For more information on regions, see Cloud build locations.

Validate the provenance metadata

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

By default, if Cloud Build does not generate provenance metadata, the build is still completed successfully. To overwrite this behavior and fail builds if Cloud Build does not generate provenance metadata for your image, add the requestedVerifyOption: VERIFIED option to your build configuration 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 regional pool, enabling provenance metadata and attestation generation for those images.

What's next