生成和验证 build 出处

本页介绍了如何生成 build 来源、查看输出并对其进行验证。

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

Cloud Build 支持根据 SLSA 版本 0.11.0 的规范生成符合软件工件的供应链级别 (SLSA) 3 级保证的 build 出处。

作为对 SLSA v1.0 规范的支持,Cloud Build 会在 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. Enable the Cloud Build, Container Analysis, and Artifact Registry APIs.

    Enable the APIs

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

  3. 准备好源代码。

  4. 在 Artifact Registry 中拥有代码库

生成 build 出处

以下说明介绍了如何为存储在 Artifact Registry 中的容器映像生成构建源代码:

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

    如果您使用显式 docker push 步骤将映像推送到 Artifact Registry,Cloud Build 将无法生成来源。

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

      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:容器映像的名称。
      {
      "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. 在 build 配置的 options 部分中,添加 requestedVerifyOption 选项并将其值设置为 VERIFIED

    此设置会启用来源生成,并配置 Cloud Build 以验证是否存在来源元数据。只有在生成了来源时,构建才会被标记为成功。

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

查看构建来源

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

您可以使用 Google Cloud 控制台内的安全分析侧边栏或 gcloud CLI 访问容器的 build 来源元数据。

安全性数据分析侧边栏提供了存储在 Artifact Registry 中的工件的安全信息的简要概览。

如需查看安全数据洞见面板,请执行以下操作:

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

    打开“构建记录”页面

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

  3. 区域下拉菜单中,选择您运行 build 时所在的区域。

  4. 在包含 build 的表格中,找到您要查看安全数据洞见的 build 所在的行。

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

    系统随即会显示所选工件的安全数据洞见面板。

    Build 卡片会显示来源详情和链接。您可以点击链接图标查看来源代码段。

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

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

  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 哈希值。您可以在 build 的输出中找到此值。
  • 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 字段采用基数 16(十六进制)编码。如果您使用的是 SLSA 版本 0.1 的来源,则输出将使用以 base 64 编码的 fileHash 字段。

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

  • 服务账号:Cloud Build 历史记录中自动包含的签名可帮助您验证执行了构建的构建服务。您还可以配置 Cloud Build 来记录有关用于启动 build 的服务账号的可验证元数据。如需了解详情,请参阅使用 cosign 对容器映像进行签名

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

查看非容器工件的来源

当您将 build 工件上传到 Artifact Registry 时,Cloud Build 会为独立的 Go、Java (Maven)、Python 和 Node.js (npm) 应用生成 SLSA 来源元数据。您可以通过发出直接 API 调用来检索来源元数据。

  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'
    

    您必须使用 API 调用来访问此类工件的来源元数据。非容器工件的来源元数据不会显示在 Google Cloud 控制台中,也无法通过 gcloud CLI 访问。

  3. 在项目的出现次数中,按 BuildID 搜索,以查找与 build 工件关联的来源信息。

验证出处

本部分介绍了如何验证容器映像的构建来源。

验证 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 哈希值。您可以在构建的输出中找到此值。
  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 验证来源元数据

如果您要验证 build 来源元数据是否未被篡改,可以执行以下步骤来验证来源:

  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

后续步骤