Google Cloud CLI の使用を開始する(GKE)


このチュートリアルでは、証明書を要求する Binary Authorization ポリシーの構成とテストの方法を説明します。このタイプのポリシーは、イメージのデプロイを許可する前に、コンテナ イメージに署名付き証明書があることを確認して、コンテナベースのソフトウェア サプライ チェーンを保護します。

デプロイ時に、Binary Authorization は認証者を使用して証明書のデジタル署名を検証します。証明書は、通常は継続的インテグレーション(CI)パイプラインの一部として署名者によって作成されます。

このチュートリアルでは、GKE クラスタ、証明書、認証者はすべて 1 つのプロジェクトに存在します。単一プロジェクト構成はサービスのテストや試験運用に非常に役立ちます。より現実的な例については、マルチプロジェクト構成をご覧ください。

以下では、コマンドラインで実行するタスクについて説明します。以下の手順を Google Cloud コンソールで行うには、Google Cloud コンソールの使用を開始するをご覧ください。

目標

このチュートリアルでは、以下の方法について学習します。

  • Binary Authorization を有効にして Google Kubernetes Engine(GKE)クラスタを作成する
  • Binary Authorization 施行者が証明書の署名を検証するために使用する認証者を作成する
  • 証明書を要求するポリシーを構成する
  • 証明書に署名して後で検証するための暗号鍵ペアを作成する
  • 署名を作成してコンテナ イメージ ダイジェストに署名する
  • 署名を使用して証明書を作成する
  • コンテナ イメージを GKE にデプロイしてポリシーをテストする

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Google Cloud CLI をインストールします。
  5. gcloud CLI を初期化するには:

    gcloud init
  6. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  7. Google Cloud プロジェクトで課金が有効になっていることを確認します

  8. Google Cloud CLI をインストールします。
  9. gcloud CLI を初期化するには:

    gcloud init
  10. GKE を操作するために kubectl をインストールします。

Binary Authorization を有効にする

デフォルト プロジェクトを設定する

まず、gcloud コマンドでデフォルトの Google Cloud プロジェクトを設定します。

PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}

ここで PROJECT_ID はプロジェクトの名前です。

必要な API を有効にする

以下の API を有効にします。

Container Registry

gcloud --project=${PROJECT_ID} \
    services enable\
    container.googleapis.com\
    containerregistry.googleapis.com\
    binaryauthorization.googleapis.com

Artifact Registry

gcloud --project=${PROJECT_ID} \
    services enable\
    container.googleapis.com\
    artifactregistry.googleapis.com\
    binaryauthorization.googleapis.com

Binary Authorization を有効にしたクラスタを作成する

クラスタを作成する

Binary Authorization を有効にした GKE クラスタを作成します。このクラスタで、デプロイしたコンテナ イメージを実行します。クラスタを作成するときに、--binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE フラグを gcloud container clusters create コマンドに渡します。

クラスタの作成手順は次のとおりです。

gcloud container clusters create \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE \
    --zone us-central1-a \
    test-cluster

ここでは、GKE ゾーン us-central1-atest-cluster というクラスタを作成します。

kubectl を構成する

kubectl のインストール用にローカルの kubeconfig ファイルも更新する必要があります。これにより、GKE でクラスタにアクセスするために必要な認証情報とエンドポイント情報が提供されます。

ローカル kubeconfig ファイルを更新するには:

gcloud container clusters get-credentials \
    --zone us-central1-a \
    test-cluster

デフォルトのポリシーを表示する

Binary Authorization ポリシーは、コンテナ イメージのデプロイを制御する一連のルールです。プロジェクトごとに 1 つのポリシーを作成できます。デフォルトでは、すべてのコンテナ イメージをデプロイできるポリシーが構成されています。

Binary Authorization を使用すると、YAML 形式のポリシー ファイルをエクスポートまたはインポートできます。この形式は、サービスによって保存されたポリシーの構造を反映しています。gcloud コマンドでポリシーを構成する場合は、このファイルを編集します。

デフォルト ポリシーを表示するには、ポリシーの YAML ファイルをエクスポートします。

gcloud container binauthz policy export

デフォルトでは、このファイルの内容は次のようになっています。

admissionWhitelistPatterns:
- namePattern: gcr.io/google_containers/*
- namePattern: gcr.io/google-containers/*
- namePattern: k8s.gcr.io/**
- namePattern: gke.gcr.io/**
- namePattern: gcr.io/stackdriver-agents/*
globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/${PROJECT_ID}/policy

デフォルトのリストには、オープンソースのコミュニティ所有のレジストリ k8s.gcr.io が含まれています。このレジストリは、registry.k8s.io に置換され、下位互換性のリストに保存されます。置換レジストリ registry.k8s.io はデフォルトのリストに含まれていません。k8s.gcr.io から移行する場合は、自分の制御下にあるレジストリに移動するか、このリストに置換レジストリ registry.k8s.io を追加します。

デフォルト ルールは defaultAdmissionRule ノードに定義されています。evaluationMode は、イメージのデプロイ時にすべての試行を許可することを指定します。このチュートリアルでは、証明書を要求するようにデフォルト ルールを更新します。

ポリシーの構造については、ポリシー YAML リファレンスをご覧ください。

認証者を作成する

認証者は、デプロイ時に Binary Authorization 施行者が GKE で対応する署名付きコンテナ イメージのデプロイを許可するかどうかを決定する際に使用する検証機関です。認証者には公開鍵が含まれ、通常は、ソフトウェア サプライ チェーンのセキュリティを担当する組織の担当者が管理します。

認証者を作成するには、次のことを行います。

  • Artifact Analysisメモを作成して、認証プロセスで使用される信頼できるメタデータを保存する
  • Binary Authorization で認証者を作成し、作成したメモを関連付ける

このチュートリアルでは、test-attestor という認証者と test-attestor-note という Container Analysis メモを使用しています。実際のシナリオでは、任意の数の認証者を指定できます。各認証者は、コンテナ イメージの認証プロセスに参加する当事者を表します。

Artifact Analysis メモを作成する

  1. 認証者の名前と Artifact Analysis メモを格納する変数を設定します。

    ATTESTOR_NAME=test-attestor
    NOTE_ID=test-attestor-note
    

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

    • test-attestor: 選択した認証者の名前。
    • attestor-note: 選択した認証者のメモ名。
  2. Container Analysis メモを記述する JSON ファイルを /tmp/note_payload.json に作成します。

    cat > /tmp/note_payload.json << EOM
    {
      "name": "projects/${PROJECT_ID}/notes/${NOTE_ID}",
      "attestation": {
        "hint": {
          "human_readable_name": "Attestor Note"
        }
      }
    }
    EOM
    
  3. HTTP リクエストを Artifact Analysis REST API に送信して、メモを作成します。

    curl -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
        --data-binary @/tmp/note_payload.json  \
        "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"
    
  4. メモが作成されたことを確認します。

    curl \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"
    

認証者を作成する

これで認証者を作成できます。

  1. Binary Authorization で認証者を作成します。

    gcloud container binauthz attestors create ${ATTESTOR_NAME} \
    --attestation-authority-note=${NOTE_ID} \
    --attestation-authority-note-project=${PROJECT_ID}
    
  2. 認証者が作成されたことを確認します。

    gcloud container binauthz attestors list
    

作成した認証者は、以下で作成する PKIX 鍵ペアが関連付けられていないため、まだ使用できません。

鍵ペアを生成する

Binary Authorization は、暗号鍵を使用して署名者の ID を安全に確認します。これにより、承認済みのコンテナ イメージのみをデプロイできます。鍵ペアは秘密鍵と公開鍵で構成されます。署名者は、署名を生成して証明書に保存し、秘密鍵を使用してコンテナ イメージのダイジェストに署名します。公開鍵は認証者に保存されます。コンテナのデプロイを許可する前に、Binary Authorization の施行者が認証者の公開鍵を使用して、証明書の署名を検証します。

このチュートリアルでは、暗号鍵に公開鍵基盤(X.509)(PKIX)形式を使用します。このチュートリアルでは、PKIX 鍵ペアの生成に推奨の 楕円曲線デジタル署名アルゴリズム(ECDSA)を使用していますが、RSA 鍵または PGP 鍵で署名することもできます。

署名アルゴリズムの詳細については、鍵の目的とアルゴリズムをご覧ください。

Cloud Key Management Service(Cloud KMS)によって生成され、保存された鍵は PKIX に準拠しています。PKIX 鍵と Cloud KMS の使用方法については、gcloud CLI を使用した認証者の作成をご覧ください。

PKIX(Cloud KMS)

Cloud KMS で鍵ペアを作成する手順は次のとおりです。

  1. 鍵ペアの作成に必要な環境変数を設定します。

    KMS_KEY_PROJECT_ID=${PROJECT_ID}
    KMS_KEYRING_NAME=my-binauthz-keyring
    KMS_KEY_NAME=my-binauthz-kms-key-name
    KMS_KEY_LOCATION=global
    KMS_KEY_PURPOSE=asymmetric-signing
    KMS_KEY_ALGORITHM=ec-sign-p256-sha256
    KMS_PROTECTION_LEVEL=software
    KMS_KEY_VERSION=1
    
  2. キーリングを作成するには、次のコマンドを実行します。

    gcloud kms keyrings create ${KMS_KEYRING_NAME} \
      --location ${KMS_KEY_LOCATION}
    
  3. 鍵を作成するには、次のコマンドを実行します。

    gcloud kms keys create ${KMS_KEY_NAME} \
      --location ${KMS_KEY_LOCATION} \
      --keyring ${KMS_KEYRING_NAME}  \
      --purpose ${KMS_KEY_PURPOSE} \
      --default-algorithm ${KMS_KEY_ALGORITHM} \
      --protection-level ${KMS_PROTECTION_LEVEL}
    
  4. 認証者に公開鍵を追加するには、次のコマンドを実行します。

    gcloud --project="${PROJECT_ID}" \
        container binauthz attestors public-keys add \
        --attestor="${ATTESTOR_NAME}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    
  5. 次のように、認証者から公開鍵 ID を取得します。

    公開鍵 ID は、gcloud container binauthz attestors describe <var>ATTESTOR_NAME</var> コマンドでいつでも確認できます。

    公開鍵 ID を環境変数に格納するには、次のコマンドを入力します。

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
    --format='value(userOwnedGrafeasNote.publicKeys[0].id)' --project ${PROJECT_ID})
    

PKIX(ローカル鍵)

PKIX 鍵ペアの生成手順は次のとおりです。

  1. 秘密鍵を作成します。

    PRIVATE_KEY_FILE="/tmp/ec_private.pem"
    openssl ecparam -genkey -name prime256v1 -noout -out ${PRIVATE_KEY_FILE}
    
  2. 秘密鍵から公開鍵を抽出します。

    PUBLIC_KEY_FILE="/tmp/ec_public.pem"
    openssl ec -in ${PRIVATE_KEY_FILE} -pubout -out ${PUBLIC_KEY_FILE}
    
  3. 認証者に公開鍵を追加します。

    次に、エクスポートした公開鍵を認証者に追加して、Binary Authorization で本人確認に使用できるようにします。

    gcloud --project="${PROJECT_ID}" \
        beta container binauthz attestors public-keys add \
        --attestor="${ATTESTOR_NAME}" \
        --pkix-public-key-file=${PUBLIC_KEY_FILE} \
        --pkix-public-key-algorithm=ecdsa-p256-sha256
    
  4. 公開鍵 ID を保存します。

    公開鍵 ID を保存するには、上記の public-keys add の出力から ID をコピーします。認証者に追加した公開鍵 ID を表示するには、gcloud container binauthz attestors describe ${ATTESTOR_NAME} を使用します。

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
      --format='value(userOwnedGrafeasNote.publicKeys[0].id)')
    

ポリシーを構成する

これで、ポリシーを構成できます。この手順では、ポリシー YAML ファイルをローカル システムにエクスポートし、上記で定義した認証者による証明書を要求するようにデフォルト ルールを変更します。

ポリシーの構成手順は次のとおりです。

  1. Google 管理のシステム イメージを許可する新しいポリシー ファイルを作成します。evaluationModeREQUIRE_ATTESTATION を設定し、作成した認証者を参照するノードを requireAttestationsBy という名前で追加します。

    cat > /tmp/policy.yaml << EOM
        globalPolicyEvaluationMode: ENABLE
        defaultAdmissionRule:
          evaluationMode: REQUIRE_ATTESTATION
          enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
          requireAttestationsBy:
            - projects/${PROJECT_ID}/attestors/${ATTESTOR_NAME}
        name: projects/${PROJECT_ID}/policy
    EOM
    
  2. ポリシー YAML ファイルを Binary Authorization にインポートします。

    gcloud container binauthz policy import /tmp/policy.yaml
    

ポリシーの構成の詳細については、gcloud CLI を使用してポリシーを構成するをご覧ください。

ポリシーのテスト

上記で構成したポリシーをテストするには、サンプル コンテナ イメージをクラスタにデプロイします。必要な証明書が作成されていないため、ポリシーによってデプロイがブロックされます。

このチュートリアルでは、Container Registry と Artifact Registry のサンプル イメージを使用できます。Container Registry のイメージは、パス gcr.io/google-samples/hello-app:1.0 にあります。Artifact Registry のイメージはパス us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 にあります。どちらのパスにも、「Hello, World!」サンプル アプリケーションを含む Google 作成の公開イメージが含まれています。

まず、イメージをデプロイします。

kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080

次に、Binary Authorization でデプロイがブロックされたことを確認します。

kubectl get pods

このコマンドを実行すると、イメージがデプロイされなかったことを示す次のメッセージが出力されます。

No resources found.

次のコマンドによってデプロイの詳細を確認できます。

kubectl get event --template \
'{{range.items}}{{"\033[0;36m"}}{{.reason}}:{{"\033[0m"}}\{{.message}}{{"\n"}}{{end}}'

次のようなレスポンスが表示されます。

FailedCreate: Error creating: pods POD_NAME is forbidden: admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image IMAGE_NAME denied by Binary Authorization default admission rule. Image IMAGE_NAME denied by attestor ATTESTOR_NAME: No attestations found

この出力で:

  • POD_NAME: Pod の名前。
  • IMAGE_NAME: イメージの名前。
  • ATTESTOR_NAME: 認証者の名前。

デプロイを削除して次の手順に進みます。

kubectl delete deployment hello-server

証明書を作成する

証明書は、関連するコンテナ イメージのデプロイを GKE が許可されていることを証明する、署名者によって作成されるデジタル ドキュメントです。証明書を作成するプロセスを「イメージに署名する」という場合があります。署名者は人の場合もあれば、コンテナ イメージのビルド時に実行される自動プロセスである場合もあります。署名は、鍵ペアの秘密鍵を使用して作成されます。デプロイ時に、Binary Authorization 施行者は認証者の公開鍵を使用して証明書の署名を検証します。

このチュートリアルでは、イメージのデプロイが承認されていることのみを証明します。

証明書の作成手順は次のとおりです。

  1. イメージのレジストリパスとダイジェストを格納する変数を設定します。

    Container Registry

    IMAGE_PATH="gcr.io/google-samples/hello-app"
    IMAGE_DIGEST="sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4"
    IMAGE_TO_ATTEST=${IMAGE_PATH}@${IMAGE_DIGEST}
    

    Artifact Registry

    IMAGE_PATH="us-docker.pkg.dev/google-samples/containers/gke/hello-app"
    IMAGE_DIGEST="sha256:37e5287945774f27b418ce567cd77f4bbc9ef44a1bcd1a2312369f31f9cce567"
    IMAGE_TO_ATTEST=${IMAGE_PATH}@${IMAGE_DIGEST}
    
  2. 証明書の作成手順は次のとおりです。

    PKIX Cloud KMS

    Cloud KMS 鍵を使用して証明書を作成するには、次のコマンドを実行します。

    gcloud beta container binauthz attestations sign-and-create \
        --project="${PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="${ATTESTOR_NAME}" \
        --attestor-project="${PROJECT_ID}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    

    PKIX(ローカル鍵)

    ローカル鍵を使用して証明書を作成する手順は次のとおりです。

    1. 証明書ペイロードを生成します。

      gcloud container binauthz create-signature-payload \
      --artifact-url=${IMAGE_TO_ATTEST} > /tmp/generated_payload.json
      

      ペイロード JSON ファイルの内容は次のとおりです。

      {
      "critical": {
        "identity": {
          "docker-reference": "gcr.io/google-samples/hello-app"
        },
        "image": {
          "docker-manifest-digest": "sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea
      882eb722c3be4"
        },
        "type": "Google cloud binauthz container signature"
      }
      }
      
    2. PKIX 秘密鍵でペイロードに署名し、署名ファイルを生成するには、次のコマンドを実行します。

      openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} /tmp/generated_payload.json > /tmp/ec_signature
      

      この署名ファイルは、このガイドの前半で作成したペイロード JSON ファイルの署名付きバージョンです。

    3. 証明書を作成して検証します。

      gcloud container binauthz attestations create \
        --project="${PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="projects/${PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
        --signature-file=/tmp/ec_signature \
        --public-key-id="${PUBLIC_KEY_ID}" \
        --validate
      

      PUBLIC_KEY_ID は、上記の PKIX 鍵ペアを生成するにある公開鍵 ID に置き換えます。

      validate フラグは、ポリシーで構成した認証者が証明書を検証できることを確認します。

  3. 証明書が作成されたことを確認します。

    gcloud container binauthz attestations list \
        --attestor=$ATTESTOR_NAME --attestor-project=$PROJECT_ID
    

証明書の作成の詳細については、証明書の作成をご覧ください。

ポリシーを再テストする

クラスタにサンプル コンテナ イメージをデプロイして、ポリシーを再度テストします。今回は、Binary Authorization はイメージパスとダイジェストの両方を使用して証明書を検索するため、1.0latest などのタグではなく、ダイジェストを使用してイメージをデプロイする必要があります。ここでは、必要な証明書が作成されたため、Binary Authorization はイメージのデプロイを許可します。

イメージのデプロイ手順は次のとおりです。

kubectl run hello-server --image ${IMAGE_TO_ATTEST} --port 8080

イメージがデプロイされたことを確認するには:

kubectl get pods

このコマンドを実行すると、デプロイが成功したことを示す次のようなメッセージが出力されます。

NAME                            READY     STATUS    RESTARTS   AGE
hello-server-579859fb5b-h2k8s   1/1       Running   0          1m

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

GKE で作成したクラスタを削除します。

gcloud container clusters delete \
    --zone=us-central1-a \
    test-cluster

次のステップ