安全なビルドとCloud Build、Artifact Registry、GKE を使用してデプロイする

安全なビルドとCloud Build、Artifact Registry、GKE を使用してデプロイする

この Codelab について

subject最終更新: 3月 4, 2023
account_circle作成者: Christopher Grant

1. はじめに

Container Analysis は、コンテナの脆弱性スキャンとメタデータ ストレージを提供します。スキャン サービスは、Artifact Registry と Container Registry 内のイメージに対して脆弱性スキャンを実行し、生成されたメタデータを保存し、API を通じて利用できるようにします。メタデータ ストレージを使用すると、脆弱性スキャン、Google Cloud サービス、サードパーティ プロバイダなど、さまざまなソースからの情報を保存できます。

脆弱性スキャンは、自動またはオンデマンドで起動できます。

  • 自動スキャンを有効にすると、Artifact Registry または Container Registry に新しいイメージを push するたびに、自動的にスキャンがトリガーされます。脆弱性情報は、新しい脆弱性が発見されると継続的に更新されます。
  • オンデマンド スキャンが有効になっている場合は、ローカル イメージ、または Artifact Registry または Container Registry 内のイメージをスキャンするコマンドを実行する必要があります。オンデマンド スキャンでは、コンテナを柔軟にスキャンできます。たとえば、レジストリに保存する前に、ローカルで作成されたイメージをスキャンして脆弱性を修正できます。スキャンの結果は、スキャン完了後最大 48 時間利用できます。スキャン後、脆弱性情報は更新されません。

Container Analysis を CI/CD パイプラインに統合すると、そのメタデータに基づいて意思決定を行うことができます。たとえば、Binary Authorization を使用して、信頼できるレジストリにあるコンプライアンス イメージのデプロイのみを許可するデプロイ ポリシーを作成できます。

学習内容

  • 自動スキャンを有効にする方法
  • オンデマンド スキャンの実行方法
  • ビルド パイプラインにスキャンを統合する方法
  • 承認済みのイメージに署名する方法
  • GKE アドミッション コントローラを使用してイメージをブロックする方法
  • 署名付きの承認されたイメージのみを許可するように GKE を構成する方法

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 米ドル分の無料トライアル プログラムをご利用いただけます。

Cloudshell エディタを起動する

このラボは、Google Cloud Shell エディタで使用するように設計、テストされています。エディタにアクセスするには、

  1. https://console.cloud.google.com から Google プロジェクトにアクセスします。
  2. 右上にある Cloud Shell エディタのアイコンをクリックします。

8560cc8d45e8c112.png

  1. ウィンドウの下部に新しいペインが開きます

環境設定

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

3. 自動スキャン

新しいイメージを Artifact Registry または Container Registry に push するたびに、アーティファクト スキャンが自動的にトリガーされます。脆弱性情報は、新しい脆弱性が発見されると継続的に更新されます。このセクションでは、イメージを Artifact Registry に push し、結果を確認します。

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

mkdir vuln-scan && cd vuln-scan

サンプル画像を定義する

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

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 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 する。イメージの bad タグに注目してください。これは、後のステップで識別するのに役立ちます。

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

画像の詳細を確認

ビルドプロセスが完了したら、Artifact Registry ダッシュボードでイメージと脆弱性の結果を確認します。

  1. Cloud コンソールで Artifact Registry を開きます。
  2. artifact-scanning-repo をクリックして内容を表示します
  3. 画像の詳細をクリックします。
  4. イメージの最新ダイジェストをクリックします
  5. スキャンが完了したら、イメージの [脆弱性] タブをクリックします。

[脆弱性] タブに、ビルドしたイメージの自動スキャンの結果が表示されます。

361be7b3bf293fca.png

デフォルトでは、スキャンの自動化が有効になっています。Artifact Registry の設定を確認し、自動スキャンのオンとオフを切り替える方法を確認する。

4. オンデマンド スキャン

イメージをリポジトリに push する前にスキャンの実行が必要になるシナリオはさまざまです。たとえば、コンテナ デベロッパーはコードをソース管理に push する前に、イメージをスキャンして問題を修正できます。以下の例では、結果をローカルでビルドして分析してから、結果を処理します。

イメージをビルドする

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

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

画像をスキャン

イメージがビルドされたら、イメージのスキャンをリクエストします。スキャンの結果はメタデータ サーバーに保存されます。ジョブはメタデータ サーバー内の結果の場所を指定して完了します。

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

出力ファイルの確認

前のステップの出力(scan_id.txt ファイルに保存されていた)を確認します。メタデータ サーバーでのスキャン結果のレポートの場所に注目してください。

cat scan_id.txt

詳細なスキャン結果を確認する

実際のスキャン結果を表示するには、出力ファイルに記載されているレポートの場所に対して list-vulnerabilities コマンドを使用します。

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

出力には、イメージ内のすべての脆弱性に関する大量のデータが含まれます。

重大な問題を報告する

ユーザーがレポートに保存されたデータを直接使用することはほとんどありません。通常、結果は自動プロセスによって使用されます。以下のコマンドを使用してレポートの詳細を確認し、重大な脆弱性が見つかった場合はログに記録します。

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

このコマンドの出力は、

Failed vulnerability check for CRITICAL level

5. パイプライン スキャンの構築

このセクションでは、コンテナ イメージをビルドしてスキャンし、結果を評価する自動ビルド パイプラインを作成します。重大な脆弱性が見つからなければ、イメージがリポジトリに push されます。重大な脆弱性が見つかった場合、ビルドは失敗して終了します。

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 パイプラインを作成する

次のコマンドにより、自動プロセスに使用される 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']

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

CI パイプラインを実行する

重大度が「CRITICAL」の脆弱性が見つかった場合、ビルドが中断されることを確認するため、処理のためにビルドを送信します。

gcloud builds submit

ビルドエラーを確認

イメージに重大な脆弱性が含まれているため、送信したビルドは失敗します。

Cloud Build の履歴ページでビルドエラーを確認する

脆弱性の修正

重大な脆弱性を含まないベースイメージを使用するように Dockerfile を更新する。

次のコマンドを使用して、Debian 10 イメージを使用するように 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

適切なイメージで CI プロセスを実行する

そのビルドを送信して処理し、重大な脆弱性が見つからなくてもビルドが成功することを確認します。

gcloud builds submit

ビルドの成功を確認

更新されたイメージには重大な脆弱性がないため、送信したビルドは成功します。

Cloud Build の履歴ページでビルドの成功を確認する

スキャン結果の確認

Artifact Registry で正常なイメージを確認する

  1. Cloud コンソールで Artifact Registry を開きます。
  2. artifact-scanning-repo をクリックして内容を表示します
  3. 画像の詳細をクリックします。
  4. イメージの最新ダイジェストをクリックします
  5. イメージの脆弱性タブをクリックする

6. イメージに署名する

認証者のメモを作成する

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

メモを作成する

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}"

認証者の作成

認証者は実際のイメージ署名プロセスを実行するために使用され、後で検証できるようにメモのオカレンスをイメージに添付します。後で使用するために認証者を作成します。

認証者を作成

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 鍵の追加

認証者には、メモを添付して検証可能な署名を提供するために暗号鍵が必要です。このステップでは、Cloud Build が後でアクセスできるように、鍵を作成して 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

署名付き構成証明の作成

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

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}

7. Cloud Build を使用した署名

イメージ署名を有効にし、認証者を手動で使用してサンプル イメージに署名しました。実際には、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 でカスタムビルド ステップを使用して、証明書プロセスを簡素化します。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 の履歴ページを開き、最新のビルドとビルドステップが正常に実行されたことを確認します。

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

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

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

GKE クラスタを作成する

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
  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

9. GKE で脆弱性をブロックする

このセクションでは、CI/CD パイプラインを Cloud Build に実装し、イメージのスキャンと脆弱性のチェックを行ってから、イメージに署名してデプロイを試みることで、これまでに学んだことを組み合わせます。GKE は Binary Authorization を使用して、イメージの実行を許可する前に、脆弱性スキャンによる署名がイメージにあることを確認します。

d5c41bb89e22fd61.png

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

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

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

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

ポリシーを適用する

gcloud beta container binauthz policy import binauth_policy.yaml

未署名のイメージのデプロイを試行する

次のコマンドを使用して、先ほどビルドしたアプリケーションのデプロイ記述子を作成します。ここで使用するイメージは、前にビルドしたイメージで、重大な脆弱性があり、署名済み証明書は含まれていません。

GKE アドミッション コントローラは、署名を一貫して検証するために、デプロイされる正確なイメージを知っている必要があります。これを実現するには、イメージ ダイジェストと単純なタグを使用する必要があります。

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

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

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

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

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

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

10. お疲れさまでした

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

学習した内容

  • 自動スキャンを有効にする方法
  • オンデマンド スキャンの実行方法
  • ビルド パイプラインにスキャンを統合する方法
  • 承認済みのイメージに署名する方法
  • GKE アドミッション コントローラを使用してイメージをブロックする方法
  • 署名付きの承認されたイメージのみを許可するように GKE を構成する方法

次のステップ:

クリーンアップ

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

プロジェクトの削除

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