生成并验证 build 出处

本页面介绍了如何生成 build 出处、查看输出和对其进行验证。

build 出处是关于 build 的可验证数据的集合。出处元数据包括构建映像的摘要、输入源位置、构建参数和构建时长等详细信息。您可以使用这些信息来确保所用的已构建工件准确可靠,且是由可信来源和构建器创建的。

Cloud Build 支持生成符合软件制品供应链等级 (SLSA) 3 级保证(基于 SLSA 版本 0.11.0 的规范)的构建出处。

作为对 SLSA v1.0 规范的支持的一部分,Cloud Build 在构建来源中提供 buildType 详细信息。您可以使用 buildType 架构来了解构建流程中使用的参数化模板,包括 Cloud Build 记录的值以及这些值的来源。如需了解详情,请参阅 Cloud Build buildType v1

限制

  • Cloud Build 仅为 Artifact Registry 中存储的工件生成构建出处。
  • 如需获取 SLSA v1.0 和 v0.1 出处,您必须使用触发器进行构建。如果您使用 gcloud CLI 手动启动构建,则 Cloud Build 仅提供 SLSA v0.1 出处。

准备工作

  1. 启用 Cloud Build, Container Analysis, and Artifact Registry API。

    启用 API

  2. 如需使用本指南中的命令行示例,请安装并配置 Google Cloud SDK

  3. 准备好源代码。

  4. Artifact Registry 中拥有一个代码库

生成 build 出处

以下说明介绍了如何为您存储在 Artifact Registry 中的容器映像生成 build 出处:

  1. 在构建配置文件中,添加 images 字段以将 Cloud Build 配置为在构建完成后将构建的映像存储在 Artifact Registry 中。

    如果您使用明确的 docker push 步骤将映像推送到 Artifact Registry,则 Cloud Build 无法生成出处。

    以下代码段展示了用于构建容器映像并将映像存储在 Artifact Registry 的 Docker 代码库中的构建配置:

    YAML

      steps:
      - name: 'gcr.io/cloud-builders/docker'
        args: [ 'build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE', '.' ]
      images: ['LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE']
    

    其中:

    • LOCATION:代码库的单区域或多区域位置
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • REPOSITORY:您的 Artifact Registry 代码库的名称。
    • IMAGE:容器映像的名称。

    JSON

      {
      "steps": [
          {
              "name": "gcr.io/cloud-builders/docker",
              "args": [
                  "build",
                  "-t",
                  "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE",
                  "."
              ]
          }
      ],
      "images": [
          "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE"
      ]
      }
    

    其中:

    • LOCATION:代码库的单区域或多区域位置
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • REPOSITORY:您的 Artifact Registry 代码库的名称。
    • IMAGE:容器映像的名称。
  2. 在构建配置的 options 部分中,添加 requestedVerifyOption 选项并将其值设为 VERIFIED

    此设置支持生成出处,并配置 Cloud Build 以验证是否存在出处元数据。只有在生成出处后,build 才会被标记为成功。

    YAML

    options:
      requestedVerifyOption: VERIFIED
    

    JSON

    {
        "options": {
            "requestedVerifyOption": "VERIFIED"
        }
    }
    
  3. 开始构建。

查看构建来源

本部分介绍如何查看 Cloud Build 创建的构建来源元数据。您可以提取此信息以进行审核。

您可以使用 Google Cloud 控制台中的安全性数据分析侧边栏或通过 gcloud CLI 访问容器的构建来源元数据。

控制台

安全性数据分析侧边栏简要介绍了 Artifact Registry 中存储的工件的安全信息。

如需查看“安全性数据分析”面板,请执行以下操作:

  1. 在 Google Cloud 控制台中打开构建记录页面:

    打开“构建记录”页面

  2. 选择您的项目,然后点击打开

  3. 区域下拉菜单中,选择您在其中运行构建的区域。

  4. 在包含构建的表中,找到要查看安全性数据分析的构建所在的行。

  5. 安全性数据分析列下,点击查看

    这会显示所选工件的安全性数据分析面板。

    构建卡片会显示出处详细信息和链接。您可以点击链接图标来查看出处代码段。

如需详细了解侧边栏以及如何使用 Cloud Build 帮助保护软件供应链,请参阅查看构建安全性数据分析

gcloud CLI

如需查看容器映像的出处元数据,请运行以下命令:

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

请替换以下内容:

  • LOCATION:您的代码库的单区域或多区域位置
  • PROJECT_ID:您的 Google Cloud 项目 ID。
  • REPOSITORY:您的 Artifact Registry 代码库的名称。
  • IMAGE:容器映像的名称。
  • HASH:映像的 sha256 哈希值。您可以在构建的输出中找到它。
  • FORMAT:可选设置,用于指定输出格式

输出示例

build 出处类似于以下内容:

      image_summary:
      digest: sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
      fully_qualified_digest: us-central1-docker.pkg.dev/my-project/my-repo/my-image@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
      registry: us-central1-docker.pkg.dev
      repository: my-repo
      slsa_build_level: 0
    provenance_summary:
      provenance:
      - build:
          inTotoSlsaProvenanceV1:
            _type: https://in-toto.io/Statement/v1
            predicate:
              buildDefinition:
                buildType: https://cloud.google.com/build/gcb-buildtypes/google-worker/v1
                externalParameters:
                  buildConfigSource:
                    path: cloudbuild.yaml
                    ref: refs/heads/main
                    repository: git+https://github.com/my-username/my-git-repo
                  substitutions: {}
                internalParameters:
                  systemSubstitutions:
                    BRANCH_NAME: main
                    BUILD_ID: e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
                    COMMIT_SHA: 525c52c501739e6df0609ed1f944c1bfd83224e7
                    LOCATION: us-west1
                    PROJECT_NUMBER: '265426041527'
                    REF_NAME: main
                    REPO_FULL_NAME: my-username/my-git-repo
                    REPO_NAME: my-git-repo
                    REVISION_ID: 525c52c501739e6df0609ed1f944c1bfd83224e7
                    SHORT_SHA: 525c52c
                    TRIGGER_BUILD_CONFIG_PATH: cloudbuild.yaml
                    TRIGGER_NAME: github-trigger-staging
                  triggerUri: projects/265426041527/locations/us-west1/triggers/a0d239a4-635e-4bd3-982b-d8b72d0b4bab
                resolvedDependencies:
                - digest:
                    gitCommit: 525c52c501739e6df0609ed1f944c1bfd83224e7
                  uri: git+https://github.com/my-username/my-git-repo@refs/heads/main
                - digest:
                    sha256: 154fcd4d2d65c6a35b06b98053a0829c581e223d530be5719326f5d85d680e8d
                  uri: gcr.io/cloud-builders/docker@sha256:154fcd4d2d65c6a35b06b98053a0829c581e223d530be5719326f5d85d680e8d
              runDetails:
                builder:
                  id: https://cloudbuild.googleapis.com/GoogleHostedWorker
                byproducts:
                - {}
                metadata:
                  finishedOn: '2023-08-01T19:57:10.734471Z'
                  invocationId: https://cloudbuild.googleapis.com/v1/projects/my-project/locations/us-west1/builds/e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
                  startedOn: '2023-08-01T19:56:57.451553160Z'
            predicateType: https://slsa.dev/provenance/v1
            subject:
            - digest:
                sha256: 7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
              name: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image
            - digest:
                sha256: 7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
              name: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image:latest
        createTime: '2023-08-01T19:57:14.810489Z'
        envelope:
          payload:
          eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdMWQ0LWVjNGEtNGVhNi1hY2RkLWFjOGJiMTZkY2M3OSIsICJzdGFydGVkT24iOiIyMDIzLTA4LTAxVDE5OjU2OjU3LjQ1MTU1MzE2MFoiLCAiZmluaXNoZWRPbiI6IjIwMjMtMDgtMDFUMTk6NTc6MTAuNzM0NDcxWiJ9LCAiYnlwcm9kdWN0cyI6W3t9XX19fQ==...
          payloadType: application/vnd.in-toto+json
          signatures:
          - keyid: projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/google-hosted-worker/cryptoKeyVersions/1
            sig: MEUCIQCss8UlQL2feFePRJuKTE8VA73f85iqj4OJ9SvVPqTNwAIgYyuyuIrl1PxQC5B109thO24Y6NA4bTa0PJY34EHRSVE=
        kind: BUILD
        name: projects/my-project/occurrences/71787589-c6a6-4d6a-a030-9fd041e40468
        noteName: projects/argo-qa/notes/intoto_slsa_v1_e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
        resourceUri: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
        updateTime: '2023-08-01T19:57:14.810489Z'
    

在此示例中,需要注意以下几点:

  • 来源构建是从 GitHub 代码库触发的

  • 对象参考:名为 digestfileHash 的字段引用同一个对象。示例输出中包含的 digest 字段以 base 16 编码(十六进制编码)。如果您使用的是 SLSA 0.1 版出处,则输出将使用以 base 64 编码的 fileHash 字段。

  • 签名:如果您使用的是 SLSA 0.1 版出处,则您的输出在 envelope 字段中包含两个签名。第一个签名的密钥名称为 provenanceSigner,使用符合 DSSE 标准的签名(采用预身份验证编码 (PAE) 格式),该签名可在 Binary Authorization 政策中进行验证。我们建议您在此证明的新用法中使用此签名。第二个签名的密钥名称为 builtByGCB,用于旧版用途。

  • 服务帐号:Cloud Build 来源中自动包含的签名可帮助您验证执行构建的构建服务。您还可以配置 Cloud Build,以记录用于启动构建的服务帐号的可验证元数据。如需了解详情,请参阅使用协同签名为容器映像签名

  • 载荷:本页面上显示的示例出处已缩短,以方便阅读。实际输出会更长,因为载荷是所有来源元数据的 base-64 编码版本。

查看非容器制品的来源

当您将构建工件上传到 Artifact Registry 时,Cloud Build 会为独立 Java (Maven)、Python 和 Node.js (npm) 应用生成 SLSA 来源元数据。

  1. 如需为工件生成出处元数据,请使用 Cloud Build 运行构建。请使用以下指南之一:

    构建完成后,请注意 BuildID

  2. 在终端中运行以下 API 调用,其中 PROJECT_ID 是与您的 Google Cloud 项目关联的 ID:

    alias gcurl='curl -H"Authorization: Bearer $(gcloud auth print-access-token)"'
        gcurl 'https://containeranalysis.googleapis.com/v1/projects/PROJECT_ID/occurrences'
    

    在项目的发生实例中,按 BuildID 进行搜索,以查找与每个构建工件相关联的出处信息。

验证出处

本部分介绍如何验证容器映像的构建出处。

验证 build 出处有助于您:

  • 确认 build 工件是否由受信任的源代码和构建器生成
  • 确保描述构建流程的出处元数据完整且真实

如需了解详情,请参阅保护构建

使用 SLSA 验证程序验证出处

SLSA 验证程序是一种开源 CLI 工具,用于根据 SLSA 规范验证 build 完整性。

如果验证程序发现问题,会返回详细的错误消息,以帮助您更新构建流程并降低风险。

如需使用 SLSA 验证程序,请执行以下操作:

  1. slsa-verifier 代码库安装 2.1 或更高版本:

    go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@VERSION
    
  2. 在 CLI 中,为映像标识符设置一个变量:

    export IMAGE=LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH
    

    将命令中的占位值替换为以下内容:

    • LOCATION:单区域或多区域位置
    • PROJECT_ID:Google Cloud 项目 ID。
    • REPOSITORY:代码库名称。
    • IMAGE:映像名称。
    • HASH:映像的 sha256 哈希值。您可以在 build 的输出中找到此代码。
  3. 授权 gcloud CLI,以便 SLSA 验证程序可以访问您的出处数据:

    gcloud auth configure-docker LOCATION-docker.pkg.dev
    
  4. 检索映像的来源并将其存储为 JSON

    gcloud artifacts docker images describe $IMAGE --format json --show-provenance > provenance.json
    
  5. 验证出处:

    slsa-verifier verify-image "$IMAGE" \
    --provenance-path provenance.json \
    --source-uri SOURCE \
    --builder-id=BUILDER_ID
    

    其中:

    • SOURCE 是映像的源代码库 URI,例如 github.com/my-repo/my-application
    • BUILDER_ID 表示构建器的唯一 ID,例如 https://cloudbuild.googleapis.com/GoogleHostedWorker

    如果要输出经过验证的出处,以便在政策引擎中使用,请使用带有 --print-provenance 标志的上一个命令。

    输出类似于以下内容:PASSED: Verified SLSA provenanceFAILED: SLSA verification failed: <error details>

如需详细了解可选标志,请参阅选项

使用 gcloud CLI 验证出处元数据

如果要验证构建来源元数据是否未被篡改,可以通过执行以下步骤来验证出处:

  1. 创建一个新目录,并转到该目录。

    mkdir provenance && cd provenance
    
  2. 使用 keyid 字段中的信息获取公钥。

    gcloud kms keys versions get-public-key 1 --location global --keyring attestor \
      --key builtByGCB --project verified-builder --output-file my-key.pub
    
  3. payload 包含来源的 JSON 表示法,采用 base64url 编码。解码该数据并将其存储在一个文件中。

    gcloud artifacts docker images describe \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v0.1") | .envelope.payload' | tr '\-_' '+/' | base64 -d > provenance.json
    

    SLSA 版本 0.1 和 1.0 的来源类型在可用时都会进行存储。如果您要针对版本 1.0 进行过滤,请将 predicateType 更改为使用 https://slsa.dev/provenance/v1。例如:

    gcloud artifacts docker images describe \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v1") | .envelope.payload' | tr '\-_' '+/' | base64 -d > provenance.json
    
  4. 信包还包含来源的签名。解码该数据并将其存储在一个文件中。

      gcloud artifacts docker images describe LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v0.1") | .envelope.signatures[0].sig' | tr '\-_' '+/' | base64 -d > signature.bin
    

    如果您要针对版本 1.0 进行过滤,请将 predicateType 更改为使用 https://slsa.dev/provenance/v1。例如:

    gcloud artifacts docker images describe LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
    --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v1") | .envelope.signatures[0].sig' | tr '\-_' '+/' | base64 -d > signature.bin
    
  5. 上面的命令引用了由 provenanceSigner 密钥签名的第一个出处签名 (.provenance_summary.provenance[0].envelope.signatures[0])。载荷通过 PAE 格式的信封签名。为了进行验证,请运行以下命令,将出处转换为 "DSSEv1" + SP + LEN(type) + SP + type + SP + LEN(body) + SP + body 的预期 PAE 格式。

    echo -n "DSSEv1 28 application/vnd.in-toto+json $(cat provenance.json | wc -c) $(cat provenance.json)" > provenance.json
    
  6. 验证签名。

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

    验证成功后,输出为 Verified OK

后续步骤