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

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

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

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

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. Enable the Cloud Build, Container Analysis, and Artifact Registry APIs.

    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. [リージョン] プルダウン メニューで、ビルドを実行したリージョンを選択します。

  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: 出力形式を指定できるオプションの設定。

出力例

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

      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 リポジトリからトリガーされました

  • オブジェクト参照: digest という名前のフィールドと fileHash という名前のフィールドは同じオブジェクトを参照しています。サンプル出力に含まれる digest フィールドは、base16(16 進数)でエンコードされています。SLSA バージョン 0.1 の来歴を使用している場合、出力では base64 でエンコードされた fileHash フィールドが使用されます。

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

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

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

コンテナ以外のアーティファクトの来歴を表示する

Cloud Build は、ビルド アーティファクトを Artifact Registry にアップロードする際に、スタンドアロン 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 で、イメージ ID の変数を設定します。

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

次のステップ