ビルドの来歴を生成し検証する

このページでは、ビルドの来歴を生成し、出力を表示して検証する方法について説明します。

ビルドの来歴は、ビルドに関する検証可能なデータの集まりです。 来歴のメタデータには、ビルドされたイメージのダイジェスト、入力ソースの場所、ビルド引数、ビルド時間などの詳細情報が含まれます。この情報を使用して、使用しているビルド アーティファクトが正確で信頼性が高く、信頼できるソースとビルダーによって作成されていることを確認できます。

Cloud Build は、SLSA バージョン 0.11.0 の仕様に基づくソフトウェア アーティファクトのためのサプライ チェーン レベル(SLSA)レベル 3 の保証を満たすビルドの来歴の生成をサポートしています。

SLSA v1.0 仕様のサポートの一部として、Cloud Build はビルドの来歴に buildType の詳細を提供します。buildType スキーマを使用すると、ビルドプロセスに使用されるパラメータ化されたテンプレートを理解できます。これには、Cloud Build が記録する値と、それらの値のソースが含まれます。詳細については、Cloud Build buildType v1 をご覧ください。

制限事項

始める前に

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

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  2. このガイドのコマンドラインの例を使用するには、Google Cloud SDK をインストールして構成します。

  3. ソースコードを手元に用意します。

  4. Artifact Registry にリポジトリを用意します。

ビルドの来歴を生成する

次の手順では、Artifact Registry に保存するコンテナ イメージのビルドの来歴を生成する方法について説明します。

  1. ビルド構成ファイルに images フィールドを追加して、ビルドの完了後にビルドされたイメージを Artifact Registry に保存するように Cloud Build を構成します。

    明示的な docker push ステップを使用して Artifact Registry にイメージを push する場合、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 が構成されます。ビルドは、来歴が生成された場合にのみ成功としてマークされます。

    YAML

    options:
      requestedVerifyOption: VERIFIED
    

    JSON

    {
        "options": {
            "requestedVerifyOption": "VERIFIED"
        }
    }
    
  3. ビルドを開始します。

ビルドの来歴を表示する

このセクションでは、Cloud Build によって作成されたビルドの来歴メタデータを表示する方法について説明します。この情報は後で監査目的で取得できます。

コンテナのビルドの来歴のメタデータには、 Google Cloud コンソールの [セキュリティ分析] サイドパネルを使用するか、gcloud CLI を使用してアクセスできます。

Console

[セキュリティ分析情報] サイドパネルには、Artifact Registry に保存されているアーティファクトのセキュリティ情報の概要が表示されます。

[セキュリティ分析情報] パネルを表示するには:

  1. Google Cloud コンソールで [ビルド履歴] ページを開きます。

    [ビルド履歴] ページを開く

  2. ビルドのテーブルで、セキュリティ分析情報を表示するビルドの行を見つけます。

  3. [セキュリティ分析情報] 列で [表示] をクリックします。

    選択したアーティファクトの [セキュリティ分析情報] パネルが表示されます。

    [ビルド] カードに、来歴の詳細とリンクが表示されます。リンクアイコンをクリックすると、来歴スニペットを表示できます。

サイドパネルの詳細と、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: 出力形式を指定できる省略可能な設定。

出力例

ビルドの来歴は次のようになります。

      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 フィールドは、base16(16 進数)でエンコードされています。SLSA バージョン 0.1 のプロベナンスを使用している場合、出力では base 64 でエンコードされた fileHash フィールドが使用されます。

  • 署名: SLSA バージョン 0.1 のプロベナンスを使用している場合、出力の envelope フィールドには 2 つの署名が含まれます。鍵名が provenanceSigner の最初の署名は、Binary Authorization ポリシーで検証可能な DSSE 準拠の署名事前認証のエンコード(PAE)形式)を使用します。この来歴の新しい用途では、この署名を使用することをおすすめします。以前の用途には、鍵名が builtByGCB の別の署名が使用されます。

  • サービス アカウント: Cloud Build の来歴に自動的に含まれる署名は、ビルドを実行したビルド サービスの検証に役立ちます。ビルドの開始に使用されたサービス アカウントに関する検証可能なメタデータを記録するように Cloud Build を構成することもできます。詳細については、cosign を使用してコンテナ イメージに署名するをご覧ください。

  • ペイロード: このページに表示されている来歴の例は、読みやすくするために短縮されています。ペイロードはすべての来歴メタデータの base-64 エンコード バージョンであるため、実際の出力は長くなります。

  • 依存関係: ビルドファイルで指定した依存関係は、resolvedDependencies フィールドの来歴に含まれます。

コンテナ以外のアーティファクトのプロベナンスを表示する

Cloud Build は、ビルド アーティファクトを Artifact Registry にアップロードする際に、スタンドアロン 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 で検索して、ビルド アーティファクトに関連付けられたプロベナンス情報を確認します。

来歴を検証する

このセクションでは、コンテナ イメージのビルドの来歴を検証する方法について説明します。

ビルドの来歴を検証すると、次のことができます。

  • 信頼できるソースとビルダーからビルド アーティファクトが生成されていることを確認する
  • ビルドプロセスを説明する来歴メタデータが完全で信頼できることを確認する

詳細については、ビルドを保護するをご覧ください。

SLSA 検証ツールを使用して来歴を検証する

SLSA 検証ツールは、SLSA 仕様に基づいてビルドの完全性を検証するためのオープンソースの CLI ツールです。

検証ツールは問題を検出すると、ビルドプロセスの更新とリスクの軽減に役立つ詳細なエラー メッセージを返します。

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. SLSA 検証ツールがプロベナンス データにアクセスできるように、gcloud CLI を承認します。

    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 provenanceまたはFAILED: 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 には、base64url でエンコードされたプロビナンスの JSON 表現が含まれます。データをデコードしてファイルに保存します。

    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 でフィルタする場合は、https://slsa.dev/provenance/v1 を使用するように predicateType を変更します。次に例を示します。

    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 でフィルタする場合は、https://slsa.dev/provenance/v1 を使用するように predicateType を変更します。次に例を示します。

    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」が出力されます。

次のステップ