コンテナビルドの保護

コンテナビルドの保護

この Codelab について

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

1. はじめに

ead1609267034bf7.png

ソフトウェアの脆弱性とは、偶発的なシステム障害を引き起こしたり、悪意ある人物にソフトウェアを侵害する手段を与えたりする可能性がある弱点です。Container Analysis では、コンテナ内の脆弱性を検出するために、次の 2 種類の OS スキャンを行います。

  • On-Demand Scanning API を使用すると、コンテナ イメージを手動でスキャンして OS の脆弱性を検出できます。このスキャンは、ユーザーのコンピュータでローカルに行うか、Container Registry または Artifact Registry にリモートで行うことができます。
  • Container Scanning API を使用すると、OS の脆弱性検出を自動化し、イメージを Container Registry または Artifact Registry に push するたびにスキャンできます。この API を有効にすると、Go と Java の脆弱性の言語パッケージ スキャンも有効になります。

On-Demand Scanning API を使用すると、自分のコンピュータにローカルに保存されているイメージ、または Container Registry や Artifact Registry にリモートで保存されているイメージをスキャンできます。これにより、脆弱性をスキャンするコンテナをきめ細かく制御できます。オンデマンド スキャンを使用して、イメージをレジストリに保存するかどうかを決定する前に、CI/CD パイプラインでイメージをスキャンできます。

学習内容

このラボでは以下を行います。

  • Cloud Build でイメージをビルドする
  • Artifact Registry for Containers を使用する
  • 自動脆弱性スキャンを利用する
  • オンデマンド スキャンを構成する
  • Cloud Build の CICD にイメージ スキャンを追加する

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

3. Cloud Build を使用してイメージをビルドする

このセクションでは、コンテナ イメージをビルドしてスキャンし、結果を評価する自動ビルド パイプラインを作成します。重大な脆弱性が見つからなければ、イメージがリポジトリに 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"

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

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

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: ['-']


EOF

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

ビルドを送信して処理する

gcloud builds submit

ビルドの詳細を確認

ビルドプロセスが開始されたら、Cloud Build ダッシュボードで進行状況を確認します。

  1. Cloud コンソールで Cloud Build を開きます。
  2. ビルドをクリックして内容を表示する

4. コンテナ用 Artifact Registry

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

Cloud Build パイプラインを更新する

生成されたイメージを Artifact Registry に push するようにビルド パイプラインを変更する

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: ['-']

# push 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']

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

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

ビルドを送信して処理する

gcloud builds submit

5. 脆弱性を自動的にスキャン

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

画像の詳細を確認

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

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

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

361be7b3bf293fca.png

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

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

イメージをリポジトリに 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

7. Cloud Build を使用した CICD でのスキャン

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. イメージの脆弱性タブをクリックする

8. お疲れさまでした

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

学習した内容

  • Cloud Build を使用してイメージをビルドする
  • コンテナ用 Artifact Registry
  • 脆弱性を自動的にスキャン
  • オンデマンド スキャン
  • Cloud Build を使用した CICD でのスキャン

次のステップ:

クリーンアップ

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

プロジェクトの削除

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

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