生成并验证 build 出处

本页介绍了如何生成 build 出处、查看输出并验证输出。

构建出处是关于构建的一组可验证数据。来源元数据包括已构建映像的摘要、输入源位置、构建参数和构建时长等详细信息。您可以利用这些信息来确保您使用的 build 制品准确可靠,由可信的来源和 build 制作者创建。

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

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

限制

  • Cloud Build 仅为存储在 Artifact Registry 中的制品生成 build 出处信息。
  • 如需同时获取 SLSA v1.0 和 v0.1 出处,您必须使用触发器进行构建。如果您使用 gcloud CLI 手动启动 build,Cloud Build 将仅提供 SLSA v0.1 出处信息。
  • 代码库附件(包括 build 出处)不受清理政策的约束。而是当附加的图片被删除时,附件也会被删除。如需了解详情,请参阅使用清理政策管理附件

准备工作

  1. 启用 Cloud Build API、Container Analysis API 和 Artifact Registry API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    启用 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. 在 build 配置的 options 部分中,添加 requestedVerifyOption 选项并将其值设置为 VERIFIED

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

    YAML

    options:
      requestedVerifyOption: VERIFIED
    

    JSON

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

查看构建来源

本部分介绍如何查看 Cloud Build 创建的构建出处元数据。您可以获取此信息用于审核。

您可以使用 Google Cloud 控制台中的安全洞见侧边栏或使用 gcloud CLI 访问容器的 build 出处元数据。

控制台

安全性数据洞见侧边栏简要概述了存储在 Artifact Registry 中的工件的安全信息。

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

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

    打开“构建记录”页面

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

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

    此时将显示所选制品的安全性数据洞见面板。

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

如需详细了解侧边栏以及如何使用 Cloud Build 帮助保护软件供应链,请参阅查看 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 哈希值。您可以在 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) 格式),可在Binary Authorization政策中进行验证。我们建议您在新的来源使用场景中使用此签名。第二个签名(密钥名称为 builtByGCB)是为旧版用法提供的。

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

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

  • 依赖项:您在 build 文件中指定的依赖项会包含在来源信息中的 resolvedDependencies 字段中。

查看非容器制品的来源

当您将 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 出处有助于您:

  • 确认 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:项目 ID。 Google Cloud
    • 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 验证来源元数据

如果您要验证 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 | jq -r '.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 格式的信封进行签名。为了验证这一点,请运行以下命令,将来源信息转换为预期的 PAE 格式 "DSSEv1" + SP + LEN(type) + SP + type + SP + LEN(body) + SP + body

    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

后续步骤