Binary Auth によるデプロイのゲーティング

1. はじめに

Binary Authorization は、信頼できるコンテナ イメージのみが Google Kubernetes Engine(GKE)や Cloud Run にデプロイされることを保証する、デプロイ時のセキュリティ管理サービスです。Binary Authorization を使用すると、開発プロセス時に信頼できる機関によるイメージへの署名を必須にして、デプロイ時にその署名を検証できます。検証プロセスを適用することで、適切であると認められたイメージのみがビルドとリリースのプロセスに組み込まれるため、コンテナ環境をより厳格に管理できます。

次の図は、Binary Authorization/Cloud Build 設定のコンポーネントを示しています。

Cloud Build と Binary Authorization による認証パイプライン。**図 1.**Binary Authorization 証明書を作成する Cloud Build パイプライン。

このパイプラインの場合:

  1. コンテナ イメージをビルドするためのコードが Cloud Source Repositories などのソース リポジトリに push されます。
  2. 継続的インテグレーション(CI)ツールである Cloud Build がコンテナをビルドしてテストします。
  3. ビルドは、コンテナ イメージを Container Registry またはビルドしたイメージを保存する別のレジストリに push します。
  4. 暗号鍵ペアの鍵管理を提供する Cloud Key Management Service がコンテナ イメージに署名します。生成された署名は、新しく作成された証明書に保存されます。
  5. デプロイ時に、認証者は鍵ペアの公開鍵を使用して証明書を検証します。Binary Authorization は、コンテナ イメージのデプロイに署名済みの証明書を要求することで、ポリシーを適用します。

このラボでは、デプロイされたアーティファクトを保護するためのツールと手法に焦点を当てます。このラボでは、作成後に特定の環境にデプロイされていないアーティファクト(コンテナ)に焦点を当てます。

学習内容

  • 画像への署名
  • アドミッション コントロール ポリシー
  • スキャンした画像への署名
  • 署名付きイメージの承認
  • 未署名のイメージのブロック

2. 設定と要件

セルフペース型の環境設定

  1. Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。この値はいつでも更新できます。
  • プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常、それが何であるかは関係ありません。ほとんどの Codelab では、プロジェクト ID を参照する必要があります(通常は PROJECT_ID として識別されます)。生成された ID が気に入らない場合は、別のランダムな ID を生成できます。または、ご自身でお試しになることもできます。このステップを終えた後は変更できず、プロジェクト期間中は維持されます。
  • なお、3 つ目の値は、一部の API で使用される [プロジェクト番号] です。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
  1. 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に課金されないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクト全体を削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。

環境設定

Cloud Shell で、プロジェクトのプロジェクト ID とプロジェクト番号を設定します。これらを PROJECT_ID 変数と PROJECT_ID 変数として保存します。

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

サービスを有効化する

必要なサービスをすべて有効にします。

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

Artifact Registry リポジトリを作成する

このラボでは、Artifact Registry を使用してイメージの保存とスキャンを行います。次のコマンドを使用してリポジトリを作成します。

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

Artifact Registry へのアクセス時に gcloud 認証情報を使用するように Docker を構成します。

gcloud auth configure-docker us-central1-docker.pkg.dev

作業ディレクトリを作成してそのディレクトリに移動する

mkdir vuln-scan && cd vuln-scan

サンプル画像を定義する

次の内容のファイルを Dockerfile という名前で作成します。

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

main.py というファイルを作成し、次の内容を含めます。

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

イメージをビルドして AR に push する

Cloud Build を使用してコンテナをビルドし、Artifact Registry に自動的に push する。

gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image

3. 画像への署名

認証者とは

認証者

  • この担当者/プロセスは、システムの信頼チェーンにおける 1 つのリンクを担当します。
  • 暗号鍵を保持し、承認プロセスに合格したらイメージに署名します。
  • ポリシー作成者はポリシーを大まかで抽象的な方法で決定しますが、認証者はポリシーのいくつかの側面を具体的に適用する責任があります。
  • QA テスターやマネージャーなどの実在の人物の場合もあれば、CI システムの bot の場合もあります。
  • システムのセキュリティは、システムの信頼性に依存するため、秘密鍵を安全に保護することが重要です。

各ロールは、組織内の個人またはチームを表します。本番環境では、これらのロールは別々の Google Cloud Platform(GCP)プロジェクトで管理される可能性が高く、Cloud IAM を使用して限定的な方法でリソースへのアクセス権がプロジェクト間で共有されます。

a37eb2ed54b9c2eb.png

Binary Authorization の認証者は Cloud Container Analysis API 上に実装されているため、この API の仕組みをまず説明することが重要です。Container Analysis API は、メタデータを特定のコンテナ イメージに関連付けることができるように設計されています。

たとえば、Heartbleed の脆弱性を追跡するためにメモを作成するとします。セキュリティ ベンダーは、コンテナ イメージの脆弱性をテストするスキャナを作成し、侵害された各コンテナに関連付けられたオカレンスを作成します。

208aa5ebc53ff2b3.png

Container Analysis は、脆弱性の追跡とともに、汎用的なメタデータ API になるよう設計されています。Binary Authorization は Container Analysis を利用して、検証対象のコンテナ イメージに署名を関連付けます**。**Container Analysis メモは 1 人の認証者を表すために使用されます。オカレンスは、認証者が承認した各コンテナに作成され、関連付けられます。

Binary Authorization API では、「認証者」のコンセプトとこれらは Container Analysis API の対応するメモとオカレンスを使用して実装されます。

63a701bd0057ea17.png

認証者のメモを作成する

認証者メモは、適用する署名タイプのラベルとして機能する小さなデータです。たとえば、脆弱性スキャンと QA の承認を示すメモがあります。このメモは署名プロセス中に参照されます。

919f997db0ffb881.png

メモを作成する

cat > ./vulnz_note.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "Container Vulnerabilities attestation authority"
    }
  }
}
EOM

メモを保存する

NOTE_ID=vulnz_note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./vulnz_note.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"

メモを確認する

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

これで、メモが Container Analysis API 内に保存されます。

認証者の作成

認証者は実際のイメージ署名プロセスを実行するために使用され、後で検証できるようにメモのオカレンスをイメージに添付します。認証者を利用するには、Binary Authorization にメモを登録する必要があります。

ed05d438c79b654d.png

認証者を作成

ATTESTOR_ID=vulnz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

認証者を確認

gcloud container binauthz attestors list

最後の行は、後のステップで鍵を指定する NUM_PUBLIC_KEYS: 0 を示しています。

また、イメージを生成するビルドを実行すると、Cloud Build によってプロジェクトに built-by-cloud-build 認証者が自動的に作成されます。したがって、上記のコマンドは 2 つの認証者 vulnz-attestorbuilt-by-cloud-build を返します。イメージが正常にビルドされると、Cloud Build が自動的に署名を行い、イメージの証明書を作成します。

IAM ロールを追加しています

Binary Authorization サービス アカウントには、証明書のメモを表示する権限が必要です。次の API 呼び出しでアクセス権を付与する

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")

BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"


cat > ./iam_request.json << EOM
{
  'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
  'policy': {
    'bindings': [
      {
        'role': 'roles/containeranalysis.notes.occurrences.viewer',
        'members': [
          'serviceAccount:${BINAUTHZ_SA_EMAIL}'
        ]
      }
    ]
  }
}
EOM

ファイルを使用して IAM ポリシーを作成する

curl -X POST  \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @./iam_request.json \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"

KMS 鍵の追加

1e3af7c177f7a311.png

この認証者を使用するには、コンテナ イメージの署名に使用できる暗号鍵ペアを認証局で作成する必要があります。これは、Google Cloud Key Management Service(KMS)を使用して行うことができます。

まず、新しいキーを記述する環境変数をいくつか追加します。

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

一連の鍵を保持するキーリングを作成する

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

認証者用に新しい非対称署名鍵ペアを作成する

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing   \
    --default-algorithm="ec-sign-p256-sha256"

Google Cloud コンソールの [KMS] ページに鍵が表示されます。

次に、gcloud binauthz コマンドを使用して、この鍵を認証者に関連付けます。

gcloud beta container binauthz attestors public-keys add  \
    --attestor="${ATTESTOR_ID}"  \
    --keyversion-project="${PROJECT_ID}"  \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

認証機関のリストを再度出力すると、登録されている鍵が表示されます。

gcloud container binauthz attestors list

署名付き構成証明の作成

この時点で、イメージに署名できる機能が構成されました。前に作成した認証者を使用して、作業中のコンテナ イメージに署名します。

858d7e6feeb6f159.png

証明書には、認証者が特定のコンテナ イメージを検証し、クラスタ上で安全に実行できることを伝える暗号署名を含める必要があります。証明するコンテナ イメージを指定するには、そのダイジェストを決定する必要があります。

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image

DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
    --format='get(image_summary.digest)')

これで、gcloud を使用して証明書を作成できるようになりました。このコマンドは、署名に使用する鍵の詳細と、承認したいコンテナ イメージを指定するだけです。

gcloud beta container binauthz attestations sign-and-create  \
    --artifact-url="${CONTAINER_PATH}@${DIGEST}" \
    --attestor="${ATTESTOR_ID}" \
    --attestor-project="${PROJECT_ID}" \
    --keyversion-project="${PROJECT_ID}" \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

Container Analysis の用語では、これにより新しいオカレンスが作成され、認証者のメモに添付されます。すべてが想定どおりに機能するよう、証明書を一覧表示できます

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

4. アドミッション コントロール ポリシー

Binary Authorization は GKE と Cloud Run の機能で、コンテナ イメージの実行を許可する前にルールを検証できます。検証は、信頼できる CI/CD パイプラインからのリクエストでも、ユーザーが手動でイメージをデプロイしようとしている場合でも、イメージを実行するあらゆるリクエストに対して実行されます。この機能により、CI/CD パイプラインのチェックのみの場合よりも効果的にランタイム環境を保護できます。

この機能を理解するために、デフォルトの GKE ポリシーを変更して厳格な認可ルールを適用します。

GKE クラスタを作成する

Binary Authorization を有効にした GKE クラスタを作成します。

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

Cloud Build にこのクラスタへのデプロイを許可します。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/container.developer"

すべて許可ポリシー

まず、デフォルトのポリシーの状態と任意のイメージのデプロイが可能であることを確認します。

  1. 既存のポリシーを確認する
gcloud container binauthz policy export
  1. 適用ポリシーが ALWAYS_ALLOW に設定されていることに注意してください。

evaluationMode: ALWAYS_ALLOW

  1. サンプルをデプロイして、何でもデプロイできることを確認する
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. デプロイが成功したことを確認する
kubectl get pods

次のような出力が表示されます。

161db370d99ffb13.png

  1. デプロイの削除
kubectl delete pod hello-server

すべて拒否ポリシー

次に、すべてのイメージを禁止するようにポリシーを更新します。

  1. 現在のポリシーを編集可能なファイルにエクスポートします
gcloud container binauthz policy export  > policy.yaml
  1. ポリシーの変更

テキスト エディタで、EvaluationMode を ALWAYS_ALLOW から ALWAYS_DENY に変更します。

edit policy.yaml

ポリシーの YAML ファイルが次のように表示されます。

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_DENY
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy

このポリシーは比較的シンプルです。globalPolicyEvaluationMode 行は、このポリシーが Google が定義したグローバル ポリシーを拡張することを宣言します。これにより、デフォルトですべての公式 GKE コンテナを実行できます。また、このポリシーでは、他のすべての Pod が拒否されることを示す defaultAdmissionRule を宣言します。アドミッション ルールには enforcementMode 行が含まれています。この行には、このルールに準拠していないすべての Pod がクラスタ上で実行されないようにブロックするように記述されています。

より複雑なポリシーを作成する方法については、Binary Authorization のドキュメントをご覧ください。

657752497e59378c.png

  1. ターミナルを開いて新しいポリシーを適用し、変更が反映されるまで数秒待ちます。
gcloud container binauthz policy import policy.yaml
  1. サンプル ワークロードのデプロイを試す
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. デプロイに失敗し、次のメッセージが表示される
Error from server (VIOLATES_POLICY): admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image gcr.io/google-samples/hello-app:1.0 denied by Binary Authorization default admission rule. Denied by always_deny admission rule

ポリシーをすべて許可するように元に戻します。

次のセクションに進む前に、必ずポリシーの変更を元に戻してください

  1. ポリシーの変更

テキスト エディタで、evaluationMode を ALWAYS_DENY から ALWAYS_ALLOW に変更します。

edit policy.yaml

ポリシーの YAML ファイルが次のように表示されます。

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. 元に戻したポリシーを適用する
gcloud container binauthz policy import policy.yaml

5. スキャンした画像への署名

イメージ署名を有効にし、認証者を手動で使用してサンプル イメージに署名しました。実際には、CI/CD パイプラインなどの自動プロセス中に証明書を適用することをおすすめします。

このセクションでは、イメージを自動的に認証するように Cloud Build を構成します。

ロール

Cloud Build サービス アカウントに Binary Authorization 認証者 / 閲覧者のロールを追加します。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/binaryauthorization.attestorsViewer

Cloud KMS 暗号鍵の署名者 / 検証者ロールを Cloud Build サービス アカウントに追加します。(KMS ベースの署名)

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/cloudkms.signerVerifier

Cloud Build サービス アカウントに Container Analysis メモ添付者のロールを追加します。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/containeranalysis.notes.attacher

Cloud Build サービス アカウントにアクセス権を付与する

Cloud Build がオンデマンド スキャン API にアクセスするための権限が必要です。次のコマンドを使用してアクセス権を提供します。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

カスタムビルド Cloud Build ステップを準備する

Cloud Build でカスタムビルド ステップを使用して、証明書プロセスを簡素化します。Google が提供するこのカスタム ビルドステップには、プロセスを合理化するヘルパー関数が含まれています。使用する前に、カスタム ビルドステップのコードをコンテナに組み込み、Cloud Build に push する必要があります。これを行うには、次のコマンドを実行します。

git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/binauthz-attestation
gcloud builds submit . --config cloudbuild.yaml
cd ../..
rm -rf cloud-builders-community

cloudbuild.yaml に署名ステップを追加する

このステップでは、Cloud Build パイプラインに証明書ステップを追加します。

  1. 以下の署名手順を確認してください。

審査のみ。コピーしない

#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
  1. 以下のパイプライン全体を使用して、cloudbuild.yaml ファイルを作成します。
cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'



images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good
EOF

ビルドを実行する

gcloud builds submit

Cloud Build の履歴でビルドを確認する

Cloud コンソールを開いて Cloud Build の履歴ページを開き、最新のビルドとビルドステップが正常に実行されたことを確認します。

6. 署名付きイメージの承認

このセクションでは、イメージの実行を許可する前に、Binary Authorization を使用してイメージに脆弱性スキャンの署名があることを確認します。

d5c41bb89e22fd61.png

証明書を要求するように GKE ポリシーを更新する

GKE BinAuth ポリシーに clusterAdmissionRules を追加して、認証者によるイメージへの署名を必須にする

現在、クラスタは公式のリポジトリのコンテナを許可し、他のすべてのコンテナを拒否するという 1 つのルールを含むポリシーを実行しています。

次のコマンドを使用して、更新した構成でポリシーを上書きします。

COMPUTE_ZONE=us-central1-a

cat > binauth_policy.yaml << EOM
defaultAdmissionRule:
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  evaluationMode: ALWAYS_DENY
globalPolicyEvaluationMode: ENABLE
clusterAdmissionRules:
  ${COMPUTE_ZONE}.binauthz:
    evaluationMode: REQUIRE_ATTESTATION
    enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
    requireAttestationsBy:
    - projects/${PROJECT_ID}/attestors/vulnz-attestor
EOM

これで、updated_policy.yaml という新しいファイルがディスク上に作成されました。デフォルトのルールではすべてのイメージが拒否されるのではなく、まず認証者による確認がチェックされます。

822240fc0b02408e.png

新しいポリシーを Binary Authorization にアップロードします。

gcloud beta container binauthz policy import binauth_policy.yaml

署名付きイメージをデプロイする

適切なイメージのイメージ ダイジェストを取得する

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:good \
    --format='get(image_summary.digest)')

Kubernetes 構成でダイジェストを使用する

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

GKE にアプリをデプロイする

kubectl apply -f deploy.yaml

コンソールでワークロードを確認し、イメージが正常にデプロイされたことを確認します。

7. 未署名のイメージのブロック

イメージをビルドする

このステップでは、ローカル Docker を使用してローカル キャッシュにイメージをビルドします。

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad .

未署名のイメージをリポジトリに push する

docker push us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad

不正なイメージのイメージ ダイジェストを取得する

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:bad \
    --format='get(image_summary.digest)')

Kubernetes 構成でダイジェストを使用する

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

アプリを GKE にデプロイしてみる

kubectl apply -f deploy.yaml

コンソールでワークロードを確認し、デプロイが拒否されたことを示すエラーを確認します。

No attestations found that were valid and signed by a key trusted by the attestor

8. 完了

お疲れさまでした。これでこの Codelab は終了です。

学習した内容

  • 画像への署名
  • アドミッション コントロール ポリシー
  • スキャンした画像への署名
  • 署名付きイメージの承認
  • 未署名のイメージのブロック

次のステップ:

クリーンアップ

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

プロジェクトの削除

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

最終更新日: 2023 年 3 月 21 日