GKE コントロール プレーン VM の整合性を検証する


このガイドでは、Google Kubernetes Engine(GKE)がコントロール プレーン VM に使用する Compute Engine 仮想マシン(VM)イメージの整合性を検証する方法について説明します。このガイドは、コントロール プレーン ログをモニタリングし、次のことを検証するセキュリティ チームを対象としています。

  • コントロール プレーン VM が、セキュアブートと整合性モニタリングによって暗号的に検証された、本物のファームウェアやその他のブート ソフトウェアで起動したこと。
  • コントロール プレーン VM が、本物の GKE OS イメージから起動したこと。

この検証は、OS イメージや、ワーカーノードの起動時の整合性に対しても行うことができます。

このページでは、GKE におけるオプションのコントロール プレーン機能について説明します。これらの機能を使用すると、コントロール プレーンのセキュリティ ポスチャーを確認する、ユーザーが管理する鍵を使用してコントロール プレーンでの暗号化と認証情報の署名を構成するといったタスクを行えます。詳細については、GKE control plane authority についてをご覧ください。

デフォルトでは、Google Cloud はマネージド コントロール プレーンにさまざまなセキュリティ対策を適用します。このページでは、コントロール プレーンの可視性と制御性をさらに高めるオプション機能について説明します。

VM の整合性検証について

デフォルトでは、GKE コントロール プレーン インスタンスはすべて Shielded VM です。これは強化された VM であり、セキュアブート、メジャード ブート、仮想トラステッド プラットフォーム モジュール(vTPM)、UEFI ファームウェアなどのセキュリティ機能を使用します。また、すべての GKE ノードで整合性モニタリングが有効になり、ベースラインの「正常な」ブート シーケンスに照らして各 Shielded VM のブート シーケンスが検証されます。この検証では、ブート シーケンス フェーズごとに合格または不合格の結果が返され、Cloud Logging に結果が追加されます。整合性モニタリングはすべての GKE クラスタでデフォルトで有効になっています。検証の対象となるフェーズは次のとおりです。

  • アーリーブート シーケンス: UEFI ファームウェアが起動してから、ブートローダーが制御を取得するまでの間。VM ログに earlyBootReportEvent として追加されます。
  • レイトブート シーケンス: ブートローダーが制御を取得してから、オペレーティング システムのカーネルが制御を取得するまでの間。VM ログに lateBootReportEvent として追加されます。

また、GKE はコントロール プレーン VM の作成ログを Logging に追加します。このログには、マシンを識別するメタデータや、VM イメージとブート シーケンスの詳細が含まれています。Google Cloud は、GitHub の gke-vsa リポジトリに各 GKE コントロール プレーン VM イメージの検証概要証明書(VSA)を公開しています。VSA は証明書に in-toto フレームワークを使用します。クラスタのコントロール プレーン VM ログを対応する VSA に照らして検証し、コントロール プレーン ノードが想定どおりに起動したことを確認できます。

これらの検証は、次の目標を達成するうえで役立ちます。

  • コントロール プレーンのソフトウェアがセキュアブートと整合性モニタリングで保護されていて、対象のソースコードと一致しており、他の Google Cloud のお客様が使用するイメージとまったく同じであることを確認する。
  • GKE でコントロール プレーンを保護する方法の信頼性を高める。

料金

この機能は、GKE で追加料金なしで提供されます。

始める前に

始める前に、次の作業が完了していることを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得する。
  • Enable the Cloud Logging API.

    Enable the API

  • バージョン 1.29 以降を実行している GKE Autopilot モードまたは Standard モードのクラスタがすでに存在していることを確認する。

必要なロール

コントロール プレーン VM の整合性を検証するために必要な権限を取得するには、管理者に依頼して、プロジェクトに対する次の IAM ロールを付与してもらってください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

失敗したブート シーケンス フェーズを確認する

整合性モニタリングは、コントロール プレーン VM がブート シーケンスのフェーズを完了できなかった場合、またはフェーズを正常に完了した場合に、Logging にログを追加します。失敗したブートイベントを表示するには、次のコマンドを実行します。

  1. Google Cloud コンソールで、[ログ エクスプローラ] ページに移動します。

    [ログ エクスプローラ] に移動

  2. [クエリ] フィールドに次のクエリを規定します。

    jsonPayload.@type="type.googleapis.com/cloud_integrity.IntegrityEvent"
    jsonPayload.earlyBootReportEvent.policyEvaluationPassed="false" OR jsonPayload.lateBootReportEvent.policyEvaluationPassed="false"
    metadata.isKubernetesControlPlaneVM = true
    

    このクエリの falsetrue に置き換えることで、正常な起動イベントを確認することもできます。

  3. [クエリを実行] をクリックします。結果が表示されない場合、コントロール プレーン VM はすべての整合性モニタリング チェックに合格しています。結果が表示された場合は、次のステップに進んで該当のクラスタを特定します。

  4. 失敗した起動の整合性ログで、resource.labels.instance_id フィールドの値をコピーします。

  5. [クエリ] フィールドに次のクエリを規定します。

    protoPayload.@type="type.googleapis.com/google.cloud.audit.AuditLog"
    protoPayload.metadata.isKubernetesControlPlaneVM="true"
    resource.labels.instance_id="INSTANCE_ID"
    protoPayload.methodName="v1.compute.instances.insert"
    

    INSTANCE_ID は、前のステップでコピーした instance_id フィールドの値に置き換えます。

  6. [クエリを実行] をクリックします。protoPayload.metadata.parentResource.parentResourceId フィールドの値は GKE クラスタ ID です。

  7. GKE クラスタの名前を確認します。

    gcloud asset query \
        --organization=ORGANIZATION_ID \
        --statement="SELECT name FROM container_googleapis_com_Cluster WHERE resource.data.id='CLUSTER_ID';"
    

    次のように置き換えます。

    • ORGANIZATION_ID: Google Cloud 組織の数値 ID。
    • CLUSTER_ID: 前のステップで取得した protoPayload.metadata.parentResource.parentResourceId フィールドの値。

    出力は次のようになります。

    # lines omitted for clarity
    //container.googleapis.com/projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME
    

    この出力のフィールドは次のとおりです。

    • PROJECT_ID: Google Cloud プロジェクト ID。
    • LOCATION: クラスタのロケーション。
    • CLUSTER_NAME: クラスタの名前。

コントロール プレーン VM のログを見つけて調べる

GKE クラスタに対応する Compute Engine VM の作成ログは、_Default ログバケットに保存されます。クラスタ コントロール プレーン VM の作成ログを見つけてこのメタデータを取得する手順は、次のとおりです。

  1. Google Cloud コンソールで、[ログ エクスプローラ] ページに移動します。

    [ログ エクスプローラ] に移動

  2. [クエリ] フィールドに次のクエリを規定します。

    resource.type="gce_instance"
    protoPayload.methodName="v1.compute.instances.insert"
    jsonPayload.metadata.isKubernetesControlPlaneVM="true"
    
  3. [クエリを実行] をクリックします。結果が表示されない場合は、始める前にの要件をすべて満たしていることを確認してください。

  4. クエリ結果で metadata フィールドを確認します。出力は次のようになります。

    # fields omitted for clarity
    "metadata": {
      "usedResources": {
        "attachedDisks": [
          {
            "sourceImageId": "9046093115864736653",
            "sourceImage": "https://www.googleapis.com/compute/v1/projects/1234567890/global/images/gke-1302-gke1627000-cos-113-18244-85-49-c-pre",
            "isBootDisk": true
          }
    # fields omitted for clarity
    

    metadata フィールドには次の情報が含まれています。

    • usedResources: VM の作成に使用されるリソースのリスト。
    • attachedDisks: VM のブートディスク。
    • sourceImageId: VM イメージの一意の ID。
    • sourceImage: ソース VM イメージの URL。このフィールドの値の構文は https://www.googleapis.com/compute/v1/projects/PROJECT_NUMBER/global/images/IMAGE_NAME です。ここで、PROJECT_NUMBER はコントロール プレーン VM をホストする Google Cloud 所有のプロジェクトの番号、IMAGE_NAME は VM の起動に使用されたイメージの名前です。
    • isBootDisk: このディスクが VM のブートディスクとして使用されたかどうかを示す識別子(ブール値)。

コントロール プレーン VM イメージの VSA を見つけて検証する

このセクションでは、GitHub の gke-vsa リポジトリで、コントロール プレーン VM イメージに対応する VSA を見つけます。次に、ソフトウェア アーティファクトのためのサプライ チェーン レベル(SLSA)フレームワークで提供されている slsa-verifier というツールを使用して、VSA を検証します。コントロール プレーン VM の作成ログから次のデータを取得する必要があります。

  • VM イメージ ID
  • VM をホストする Google Cloud 所有プロジェクトのプロジェクト番号
  • VM の起動に使用された OS イメージの名前

コントロール プレーン VM に対応するファイルのファイル名形式は次のようになります。

IMAGE_NAME:IMAGE_ID.intoto.jsonl

次のように置き換えます。

  • IMAGE_NAME: VM イメージ名。前のセクションで説明した VM 監査ログに含まれる attachedDisks.sourceImage フィールドの、/images/ の後に続く文字列です。例: gke-1302-gke1627000-cos-113-18244-85-49-c-pre
  • IMAGE_ID: VM イメージ ID。前のセクションで説明した VM 監査ログに含まれる attachedDisks.sourceImageId フィールドの値です。例: 9046093115864736653

VSA ファイルのファイル名がわかったら、次の手順を実施して VSA を見つけて検証します。

  1. GitHub の gke-vsa リポジトリを開きます。
  2. 「gke-master-images」ディレクトリで、VM イメージに対応するファイルを見つけます。例: https://github.com/GoogleCloudPlatform/gke-vsa/blob/main/gke-master-images:78064567238/IMAGE_NAME:IMAGE_ID.intoto.jsonl
  3. VSA ファイルをダウンロードします。
  4. slsa-verifier ツールをインストールします
  5. VSA を検証するための公開鍵を vsa_signing_public_key というファイルに保存します。

    -----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeGa6ZCZn0q6WpaUwJrSk+PPYEsca
    3Xkk3UrxvbQtoZzTmq0zIYq+4QQl0YBedSyy+XcwAMaUWTouTrB05WhYtg==
    -----END PUBLIC KEY-----
    

  6. VSA を検証します。

    slsa-verifier verify-vsa \
        --attestation-path=PATH_TO_VSA_FILE \
        --resource-uri=gce_image://gke-master-images:IMAGE_NAME \
        --subject-digest=gce_image_id:IMAGE_ID\
        --verifier-id=https://bcid.corp.google.com/verifier/bcid_package_enforcer/v0.1 \
        --verified-level=BCID_L1 \
        --verified-level=SLSA_BUILD_LEVEL_2 \
        --public-key-path=PATH_TO_PUBLIC_KEY_FILE \
        --public-key-id=keystore://76574:prod:vsa_signing_public_key
    

    次のように置き換えます。

    • PATH_TO_VSA_FILE: ダウンロードした VSA ファイルのパス。
    • IMAGE_NAME: VM イメージの名前(gke-1302-gke1627000-cos-113-18244-85-49-c-pre など)。
    • IMAGE_ID: VM イメージ ID(9046093115864736653 など)。

    VSA が検証チェックに合格すると、出力は次のようになります。

    Verifying VSA: PASSED
    PASSED: SLSA verification passed
    

次のステップ