コンテンツに移動
DevOps & SRE

Google Cloud の組み込みサービスを使用して安全な CI / CD パイプラインを構築する

2022年10月11日
Google Cloud Japan Team

※この投稿は米国時間 2022 年 9 月 14 日に、Google Cloud blog に投稿されたものの抄訳です。

DevOps は、自動化された安定的な方法でソフトウェア開発チームがソフトウェアをリリースできるようにするためのコンセプトです。DevOps は 1 つのものではありません。これは文化とテクノロジーの組み合わせであり、この 2 つが合わさることで DevOps の実装が成功します。

このブログでは、DevOps のツールとテクノロジーの側面に注目します。DevOps の技術的な側面の中心にあるのは、継続的インテグレーションと継続的デリバリー(CI / CD)です。CI / CD コンセプトの背後にある考え方は、新しいソフトウェア リリースを自動的かつ継続的にデプロイする自動化されたソフトウェア デリバリー パイプラインを作成することです。

開発者がコード変更をソースコード リポジトリに commit すると、フローが開始します。そして自動的にデリバリー パイプライン(これ以降 CI / CD パイプラインという)がトリガーされ、コード変更がビルドされて非本番環境や本番環境のさまざまな環境にデプロイされます。

さらに、より迅速かつより信頼性に優れたソフトウェア デリバリーを目指して CI / CD パイプラインを構築するには、セキュリティの側面も無視できません。パイプラインには初めから、セキュリティを組み込む必要があります。ソースコードをビルドする際、通常はさまざまなオープンソース ライブラリとコンテナ イメージを使用します。構築してデプロイするソフトウェアにどんな脆弱性もないようにするには、セキュリティ対策を CI / CD パイプラインに組み込むことが必要不可欠です。これと同じく重要な点は、ターゲット ランタイム環境にどんなコード / コンテナ イメージのデプロイが許可されるかを制御することです。

セキュリティには全員が責任を持ちます。DevOps にはセキュリティに関するシフトレフトの原則があります。これに従うことで、ソフトウェア開発ライフサイクルの早期段階でセキュリティ上の懸念に対処できます。CI / CD パイプラインの安全性を強めるセキュリティ ポリシーを実装する方法には、コンテナ イメージの脆弱性スキャンを実施すること、Binary Authorization によってセキュリティ ポリシーを確立すること、承認済みまたは信頼できるイメージに限って GKE へのデプロイを許可することなどがあります。

何を構築するか

このブログ投稿では、Google Cloud の組み込みサービスを使用して安全な CI / CD パイプラインを構築する方法を説明します。ここでは、サンプル Node.js アプリケーションをコンテナ イメージとしてビルドして GKE クラスタにデプロイする、安全なソフトウェア デリバリー パイプラインを構築します。

CI / CD パイプラインの構築方法

このパイプラインを構築するには、Google Cloud の次の組み込みサービスを使用します。

  1. Cloud Build - Cloud Build は、タスクのビルド、テスト、デプロイを自動化できる完全にサーバーレスな CI / CD プラットフォームです。

  2. Artifact Registry - Artifact Registry は、ビルド アーティファクトを安全に保存して管理するためのサービスです。

  3. Cloud Deploy - Cloud Deploy は、GKE および Anthos 向けのフルマネージド継続的デリバリー サービスです。

  4. Binary Authorization - Binary Authorization は、GKE と Cloud Run のデプロイを対象としてデプロイ時のセキュリティを管理します。

  5. GKE - GKE はフルマネージドの Kubernetes プラットフォームです。

  6. Google Pub/Sub - Pub/Sub は、サーバーレスなメッセージング プラットフォームです。

  7. Cloud Functions - Cloud Functions は、サーバーレスでコードを実行できるプラットフォームです。

ソースコード リポジトリとして GitHub を使用します。また、SendGrid API を使用して、承認用とエラーログ用のメール通知を送信します。

CI / CD パイプラインをセットアップする際には、GitHub リポジトリ内の特定のリポジトリとブランチに push されたコードを検知するように Cloud Build トリガーを構成し、このトリガーによって自動的にビルドプロセスを開始します。

セキュリティ ポリシーをまったく適用せずに CI / CD パイプラインをセットアップした場合、フローは次のようになります。

  1. 開発者がコードを GitHub リポジトリにチェックインします。

  2. Cloud Build トリガーは、この GitHub リポジトリに push された新しいコードを検知するように設定され、トリガーによって「ビルド」プロセスが開始します。ビルドが正常に完了すると、結果として Docker コンテナ イメージが生成されます。

  3. コンテナ イメージが Artifact Registry に保存されます。

  4. ビルドプロセスによって Cloud Deploy デプロイ プロセスが開始します。デプロイ パイプラインとして事前構成された、テスト環境、ステージング環境、本番環境を模倣する 3 つの異なる GKE クラスタにコンテナ イメージがデプロイされます。

  5. Cloud Deploy は、承認ステップを経て本番環境の GKE クラスタにイメージをデプロイするように構成されています。

  6. Cloud Functions の関数が、事前構成されたメール ID 宛てにメールを送信し、Cloud Deploy ロールアウトに承認が必要であることを通知します。メールの受信者は、本番環境の GKE クラスタへのデプロイを承認または拒否できます。Cloud Functions の関数のコードはこちらで確認できます。

この CI / CD パイプラインをセキュリティで保護するには、Google Cloud 組み込みの機能とサービスをいくつか使用します。まず、Artifact Registry で脆弱性スキャン機能を有効にします(脆弱性スキャンはすぐに使える機能です)。次に、Binary Authorization サービスを使用してセキュリティ ポリシーを作成し、特定のイメージだけが GKE クラスタにデプロイされるようにします。

脆弱性があるコンテナ イメージをビルドしてデプロイしようと試みた場合、フローは次のようになります。

  1. 開発者がコードを GitHub リポジトリにチェックインします。

  2. Cloud Build トリガーが、この GitHub リポジトリに push された新しいコードを検知して「ビルド」プロセスを開始するように構成されます。

  3. ビルドプロセスが失敗し、イメージに脆弱性が見つかったというエラー メッセージが表示されます。

Binary Authorization ポリシーに違反するコンテナ イメージを GKE にデプロイしようと試みた場合、フローは次のようになります。

  1. 開発者がコードを GitHub リポジトリにチェックインします。

  2. Cloud Build トリガーが、この GitHub リポジトリに push された新しいコードを検知して「ビルド」プロセスを開始するように構成されます。ビルドが正常に完了すると、結果として Docker コンテナ イメージが生成されます。

  3. コンテナ イメージが Artifact Registry に保存されます。

  4. ビルドプロセスによって Cloud Deploy デプロイ プロセスが開始します。デプロイ パイプラインとして事前構成された、テスト環境、ステージング環境、本番環境を模倣する 3 つの異なる GKE クラスタにコンテナ イメージがデプロイされます。

  5. 受信されたイメージは既存の Binary Authorization ポリシーに違反するので、GKE クラスタがそれを拒否して Cloud Deploy の処理が失敗します。その場合でも、本番環境へのデプロイ前に Cloud Functions の関数によって承認メールがトリガーされることに注意してください。メール受信者には、それまでのステージでの失敗を根拠にこのリリースを拒否することが期待されます。

  6. Binary Authorization ポリシー違反によってデプロイが失敗すると、Cloud Function 関数は事前構成されたメール ID 宛てに、デプロイの失敗に関するメールを送信します。Cloud Functions の関数のコードは こちらで確認できます。

注: Cloud Deploy で設定されたタイムアウト値(デフォルトでは 10 分)を超えると、デプロイは失敗します。必要に応じてこの値を変更できます。詳しくはこちらをご覧ください。

注: ロールアウト承認メールとデプロイの失敗の通知に使用できる Cloud Functions の関数のコードは、このリポジトリの cloud-functions フォルダ内にあります。メール通知を受信するには、このコードを使用して Google Cloud プロジェクト内でこれらの Cloud Functions の関数を作成する必要があります。

ソリューション アーキテクチャ

CI / CD パイプラインは、上述の Google Cloud サービスを組み合わせて構築されます。パイプライン自動化の中心的役割を果たすのは Cloud Build です。コンテナ イメージをビルドしてデプロイするのに必要なすべてのステップが Cloud Build に含まれています。Cloud Build は、YAML ファイルで定義されたステップを順次実行します。ここでは「ビルド」と「デプロイ」のプロセスを極めて柔軟に定義できます。これらのステップは、このサービスにより毎回確実に実行されます。

以下のソリューションは、CI / CD パイプラインのセットアップ方法を示しています。

https://storage.googleapis.com/gweb-cloudblog-publish/images/A_secure_CICD_pipeline.max-1800x1800.jpeg

CI プロセスの最後のステップとして、Cloud Build YAML は Cloud Deploy サービスをトリガーします。これにより、コンテナ イメージが 3 つの異なる GKE クラスタにデプロイされます。Cloud Deploy は、デプロイ プロセス全体を通して複数の通知を自動的に Pub/Sub トピックに送信します。Cloud Functions を使用してこれらの Pub/Sub トピックをリッスンし、デプロイ ステータスと必要な承認に関する適切なメール通知を送信します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/B_secure_CICD_pipeline.max-800x800.jpeg

CI / CD パイプラインの作成手順

I. 前提条件

GCP 環境をセットアップして準備するには、この手順が必要です。「us-central1」リージョン内で複数のクラウド サービスを実行することになるので、新しい GCP プロジェクトを作成することを強くおすすめします。

  1. 次の GitHub リポジトリをフォークします: https://github.com/sysdesign-code/dev-sec-ops-demo

  2. 新しい GCP プロジェクトを作成します。プロジェクトのプロビジョニングと作成に関する次のガイドの手順に従ってください: https://cloud.google.com/resource-manager/docs/creating-managing-projects

  3. 新しいプロジェクトを作成したら、Cloud SDK を有効にして、Cloud Shell またはローカル ワークステーションで gcloud に CLI アクセスできるようにします。次のガイドの手順に従ってください: https://cloud.google.com/sdk/docs/install

  4. CLI アクセスを有効にしたら、Cloud Shell またはローカル ワークステーションでプロジェクト ID を確認するか、次のように設定します:
    gcloud config set project YOUR_PROJECT_ID

  5. ワンタイム スクリプト /scripts/gcp_env_setup.sh を実行します。これにより、サンプル Docker アプリケーションをデプロイする DevSecOps CI / CD パイプラインを作成するのに必要な GCP クラウド サービスが作成され、プロビジョニングされます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/C_secure_CICD_pipeline.max-1100x1100.jpeg

スクリプトが完了すると、次のようなサービス デプロイメントになります。

a)必要なすべてのクラウド サービス API(Cloud Build、Binary Authorization、Kubernetes Service、Artifact Registry、Cloud Deploy、その他多数)が有効にされます。

b)テスト環境用、ステージング環境用、本番環境用の 3 つの GKE クラスタが作成され、Cloud Deploy を使用してこれらのクラスタでイメージ ロールアウト デプロイが示されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/D_secure_CICD_pipeline.max-1200x1200.jpg

c)Cloud Build と Cloud Deploy に必要なすべての IAM ロールと権限がバインドされます。

d)Binary Authorization 認証者および関連するコンテナノード、暗号 KMS 鍵が作成され、認証者のコンテナ ノード アクセスを許可する関連するすべての IAM ロールと権限も作成されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/E_secure_CICD_pipeline.max-1200x1200.jpg

デフォルトで、Binary Authorization ポリシーはすべてのイメージが GCP にデプロイされることを許可します。あとでこのポリシーを更新して、認証者が承認したイメージだけが特定の GKE クラスタにデプロイされるようにします。

https://storage.googleapis.com/gweb-cloudblog-publish/images/F_secure_CICD_pipeline.max-1300x1300.jpg

e)Docker イメージを保存する Artifact Registry リポジトリが作成されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/G_secure_CICD_pipeline.max-800x800.jpg

f)最後に、2 つの Pub/Sub トピックと Cloud Functions の関数が作成されます。これにより、本番環境への GKE デプロイメントに関するメール承認と、リリースが失敗した場合のエラー報告が可能になります。

  1. スクリプトを実行する前に、新しい GCP プロジェクトに「デフォルト」の VPC とサブネットワークが含まれているかどうか確認してください。「デフォルト」VPC がある場合は、スクリプトの 53~55 行目(デフォルトの VPC とサブネットワークの作成を参照する部分)をコメントアウトします。これがすでに存在する場合は、このステップは不要です。

  2. デフォルトでは、GKE クラスタの作成で「デフォルト」VPC サブネットワークが使用されます。デフォルト以外の VPC を使用するには、157 行目以降の GKE クラスタ作成コマンドを更新し、3 つすべての GKE クラスタの --subnetwork 値を変更してください。

6. スクリプトを実行するために、次のコマンドを実行します。sh /scripts/gcp_env_setup.sh

g)このスクリプトが完了するには約 20~22 分かかります。完了すると、こちらのような出力が表示されます。

7. SendGRID API キーを作成します。https://app.sendgrid.com/guide/integrate に記載されている手順に沿って、料金のかからない「ウェブ API」メール統合を作成し、cURL とそれに関連付けられた API キーを生成します。キーの値をメモして保存し、統合を確認します。このブログで後ほど Cloud Deploy 承認プロセスを作成する際に、このキーの詳細が必要になります。注: SendGRID API を使用するには、ユーザー アカウントの作成が必要です。

II. Cloud Build を構成する

このステップで、git リポジトリ(前提条件のステップ 1)をマネージド リポジトリとして GCP の Cloud Build サービスに統合し、必要なトリガーを作成する必要があります。この統合の目標は、GitHub リポジトリ内のアプリケーションを更新すると、自動的に Cloud Build デプロイが開始されてアプリケーションが作成、有効化され、GKE にデプロイされるようにすることです。

以下の手順に沿って、Cloud Build 用の GitHub リポジトリ統合を作成します。

  1. まず、GCP コンソールのホームページで検索バーに「Cloud Build」と入力し、このサービスを選択します。

  2. 左側のパネルで [トリガー] をクリックします。次に [リポジトリを接続] をクリックします。

  3. ソースとして [GitHub(Cloud Build GitHub アプリ)] を選択します。

  4. GitHub 認証情報を使って接続を認証し、フォークされたリポジトリを選択して [接続] をクリックします。

  5. 統合が完了すると、新しく追加されたリポジトリが [トリガー] -> [リポジトリの管理] に表示されるようになります。

https://storage.googleapis.com/gweb-cloudblog-publish/images/H_secure_CICD_pipeline.max-1000x1000.jpg

Cloud Build のトリガーを作成する

  1. [トリガー] ページで [トリガーを作成] をクリックします。

  2. トリガーに設定する次の値を入力または選択します。

  • 名前: CI/CD-blog-trigger

  • リージョン: us-central1

  • 説明: GCP CI / CD クラウド サービスを使用した Docker デプロイ イメージ

  • イベント: ブランチに push する

  • リポジトリ: フォークされたリポジトリを選択します

  • ブランチ: ^main$

  • 構成: Cloud Build 構成ファイル(yaml または json)

  • ロケーション: リポジトリ

  • Cloud Build 構成ファイルの場所: / cloudbuild.yaml

  • [詳細設定] で、次の 2 つの環境変数とそれぞれの値を追加します。_CONTAINER_REPO_NAME: test-repo _SEVERITY: CRITICAL
    注: これらの環境変数の値では大文字と小文字が区別されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/I_secure_CICD_pipeline.max-1100x1100.jpg

3. 環境変数の値を入力 / 選択したら、[作成] をクリックします。

トリガーが作成されると、次のように表示されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/J_secure_CICD_pipeline.max-1000x1000.jpg

III. Cloud Deploy パイプラインを作成する

GitHub 統合と Cloud Build トリガーを作成したら、次のステップとして Cloud Deploy パイプラインを作成します。これにより、Cloud Build によって GKE の 3 つすべての環境(「テスト」、「ステージング」、「本番」)のイメージ リリースが作成されると、これらの環境にコンテナ イメージがデプロイされるようにします。イメージ リリースの要件として、Cloud Deploy パイプラインが必要です。

  1. clouddeploy.yaml ファイルを編集して GCP プロジェクト ID を設定します。

  2. ファイル内の 22 行目、32 行目、42 行目に、それぞれに対応する GCP プロジェクト ID を設定します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/K_secure_CICD_pipeline.max-2000x2000.jpg

3. ファイルの更新が完了したら、ファイルを保存します。

4. Cloud Shell またはローカル ワークステーションのいずれかで、次の GCP コマンドを実行して環境変数と ci-cd-test という名前の Cloud Deploy パイプラインを作成します。
読み込んでいます...

注: 問題が発生して Cloud Deploy パイプラインの作成に失敗した場合は、次の gcloud コマンドを使用してパイプラインを削除してください。

読み込んでいます...

5. パイプラインが作成されると、次のような出力が表示されます。

読み込んでいます...

6. GCP コンソールのホームページで検索バーに「Cloud Deploy」と入力し、このサービスを選択します。メインページに、新しく作成されたパイプラインが表示されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/L_secure_CICD_pipeline.max-1000x1000.jpg

IV. GKE の本番環境のクラスタ デプロイに関するメール通知を構成する

標準的な CI / CD プロセスの一環として、本番環境ワークロードをデプロイする場合は、DevOps エンジニアによるなんらかの形の承認プロセスが必要です。Cloud Deploy を使用すれば、次のターゲットにロールアウトをデプロイする前に「承認」ステップを挿入できます。この承認チェックは、パイプライン内の「本番環境」GKE クラスタへのデプロイの前に作成されています。パイプラインが「本番環境」GKE クラスタへのロールアウトをデプロイするためのステップに到達すると、clouddeploy-approvals Pub/Sub トピックでメッセージを出力します。このトピックをリッスンし、Sendgrid を介してメール通知を送信するためのロジックを実装する Cloud Functions の関数はすでに作成されています。他のライブラリを使用して、Cloud Functions 経由でメールを送信することもできます。

ワンタイム スクリプトによってすでに Pub/Sub トピックと Cloud Functions の関数が作成されているため、Cloud Build リリースで承認メールを送信できます。

Pub/Sub トピックと Cloud Functions の関数が作成されているかどうかは、それぞれのサービスに移動すると確認できます。

  1. GCP コンソール のホームページで検索バーに「Pub/Sub」と入力し、このサービスを選択します。clouddeploy-approvalsclouddeploy-operationsという名前の 2 つの Pub/Sub トピックが表示されます。

  2. GCP コンソール のホームページで検索バーに「Cloud Functions」と入力し、このサービスを選択します。cd-approvalcd-deploy-notification という名前の Cloud Functions の2 つの 関数が表示されます。

  3. [cd-approval] をクリックして、[変数] を選択します。

  4. [編集] ボタンをクリックして、[ランタイム、ビルド、接続、セキュリティの設定] を展開します。

  5. [ランタイム環境変数] が表示されるまで下にスクロールします。ここで、以下の 3 つの変数を更新します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/M_secure_CICD_pipeline.max-800x800.jpg

[FROM_EMAIL] に、予備のメール アカウントを入力します。これは、@gmail にすることも、他のドメインを選択することもできます。[TO_EMAIL] で、メインのメールを選択します。たとえば、GKE へのすべての本番環境ワークロード デプロイの承認者になる DevOps エンジニアのメールを選択します。[SENDGRID_API_KEY] に、「SG.」で始まる API キーを入力します。まだキーを持っていない場合は、上記「前提条件」セクションで、このキーの作成に関するステップ 6 を参照してください。

6. Cloud Functions の環境変数を更新したら、[次へ] をクリックして、更新した関数を [デプロイ] します。これには、1~2 分かかります。完了すると、関数にその実行を確認するための緑色のチェックマークが表示されます。

7. cd-approval の他の Cloud Functions の関数に対して、上記ステップ 4~6 を繰り返します。

GCP CI / CD パイプラインをテストして確認するための手順ガイド

これで、Cloud Build、Cloud Deploy、メールの各承認に関するすべての GCP 前提条件を満たし、環境のセットアップを完了したため、次は GKE にイメージをデプロイして、パイプラインのテストを開始します。

このテスト中のいくつかの注意点として、GKE への「Happy」と「Vulnerable」のイメージデプロイのパスについて見ていきます。

「Happy」パスは、GKE へのクリーン イメージ デプロイに関する 9 つのステップに及ぶエンドツーエンド パイプラインの成功したデプロイを表します。「クリーン」は、重大な脆弱性のない Docker イメージを意味します。このパスは、DevOps エンジニアが承認する、GKE の「テスト環境」、「ステージング環境」、および最終的な「本番環境」への「Happy」イメージのみのデプロイを可能にする Binary Authorization ポリシーも更新することになります。

https://storage.googleapis.com/gweb-cloudblog-publish/images/N_secure_CICD_pipeline.max-2200x2200.jpg

「Vulnerable」Docker パスは、7 つのステップに及ぶエンドツーエンド パイプラインの失敗したデプロイを表します。パイプラインは、イメージに以下が含まれているためにこれらのステップのうちの 2 つで失敗します。

  • 特定の脆弱性。イメージを Artifact Registry に保存する前に解決しておく必要があります。

  • 失敗した GKE へのデプロイ。これは、証明書のない未承認のイメージであり、「Happy」パスから更新された Binary Authorization ポリシーに違反しているためです。

Binary Authorization が有効になっている場合は、そのデフォルト ポリシーで、証明書のないすべてのイメージを GKE ターゲット環境にデプロイできます。「Happy」パスでは、GKE へのデプロイに特定の Docker イメージのみを承認する、デフォルトの Binary Authorization ポリシーを更新します。GKE は、デプロイ時に Binary Authorization ポリシーによって承認されなかった他のすべてのイメージを拒否します。

アクティブな Binary Authorization ポリシーを通して他のイメージを GKE にデプロイするには、既存の認証者へのイメージ ダイジェストに署名して、そのイメージを GKE にデプロイするためのスクリプト(/scripts/create_binauthz_policy.sh)を更新します。

以降のセクションでは、GKE へのイメージ デプロイの両方のパスについてさらに詳しく説明します。

I. 「Happy」パス用の Cloud Build 構成ファイルを実行する

  1. GitHub リポジトリが Cloud Build 内でリポジトリとして接続されていることを確認します。この方法については、「Cloud Build 用の GitHub リポジトリ インテグレーションを作成する」のセクションを参照してください。

  2. CI/CD-blog-trigger という名前の Cloud Build トリガーが作成されていることを確認します。この方法については、「Cloud Build のトリガーを作成する」のセクションを参照してください。

  3. トリガーはすでに有効になっているため、リポジトリを更新すると、この Cloud Build デプロイがトリガーされます。

  4. GitHub リポジトリから、cloudbuild.yaml を開きます。これは、「Happy」Docker パス用の Cloud Build 構成ファイルです。

  5. ビルドをキックオフするには、外観上の変更のための /src/static/js ファイルの更新など、コードベースに変更を加えます。

  6. 完了した変更を GitHub リポジトリに push します。

  7. GCP コンソール で、Cloud Build サービスに移動し、[履歴] をクリックします。

  8. トリガーが有効になっており、GitHub ページに統合されているため、ビルドが自動的にキックオフされます。カスタムビルド番号をクリックすると、ログの詳細が表示されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/O_secure_CICD_pipeline.max-900x900.jpg

II. 「Happy」パスのイメージ デプロイを検証する

  1. そのビルド内のステップ 7~9 で、Cloud Deploy を介した GKE へのイメージ デプロイが取り上げられます。ステップ 9 をクリックすると、ビルドの結果に「本番環境」へのデプロイが承認待ちであることが表示されます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/P_secure_CICD_pipeline.max-2200x2200.jpg

2. GCP コンソール から Cloud Deploy ホームページに移動して、[ci-cd-test] パイプラインをクリックします。

3. パイプライン内で、最新の Cloud Build デプロイに関連付けられたリリースをクリックします。ここで、「test」および「staging」の両方に「Happy」のイメージが正常にデプロイされていることが確認できますが、「prod」クラスタでは承認プロセスが必要です。

https://storage.googleapis.com/gweb-cloudblog-publish/images/Q_secure_CICD_pipeline.max-2200x2200.jpg

4. GCP コンソールの左側のナビゲーションから Kubernetes Engine を検索して、[ワークロード] をクリックします。ここで、「test」および「staging」の 2 つの GKE 環境にイメージが正常にデプロイされていることが確認できます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/R_secure_CICD_pipeline.max-1300x1300.jpg

5. デプロイが本番環境のキューに追加されたら、メインのメールアドレスで承認の通知メールを受信していることを確認します。内容は次のようになります。

https://storage.googleapis.com/gweb-cloudblog-publish/images/S_secure_CICD_pipeline_1.max-2000x2000.jpg

6. メールに記載の「here」のハイパーリンクをクリックして、Cloud Deploy のパイプライン ページに移動します。

7. デプロイを GKE の「prod」環境に push できるよう、パイプライン ページでリリースを承認または拒否します。この場合は承認します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/T_secure_CICD_pipeline.max-1700x1700.jpg

8. Kubernetes ワークロード ページに戻ると、prod 環境へのイメージのロールアウトが正常に行われていることを確認できます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/U_secure_CICD_pipeline.max-1500x1500.jpg

同時に、Cloud Deploy を確認します。継続的デプロイ パイプラインも正常にロールアウトされていることを確認できます。

https://storage.googleapis.com/gweb-cloudblog-publish/images/V_secure_CICD_pipeline.max-2200x2200.jpg

III. 「Vulnerable」パス用の Cloud Build 構成ファイルを実行する(コンテナ イメージに脆弱性がある場合)

このデプロイを使用した 2 つの失敗パス(イメージ脆弱性と Binary Authorization ポリシー適用)を示します。

A. 1 つ目は、重要度特有の脆弱性が原因の、Artifact Registry に Docker イメージを push するためのデプロイの失敗 -

1. GitHub リポジトリが Cloud Build 内でリポジトリとして接続されていることを確認します。この方法については、「Cloud Build 用の GitHub リポジトリ インテグレーションを作成する」のセクションを参照してください。

2. CI/CD-blog-trigger という名前の Cloud Build トリガーが作成されていることを確認します。この方法については、「Cloud Build のトリガーを作成する」のセクションを参照してください。

3. トリガーはすでに有効になっているため、リポジトリを更新すると、この Cloud Build デプロイがトリガーされます。

4. GitHub リポジトリから、cloudbuild-vulnerable.yaml ファイルを表示します。これは、「Vulnerable」Docker パス用の Cloud Build 構成ファイルです。

5. 以下を使用して既存のトリガーを編集します。

  • [実行] の横にある楕円をクリックして、[Cloud Build 構成ファイルの場所] を cloudbuild-vulnerable.yaml に更新します。

  • "_SEVERITY" 環境変数の値を HIGH に更新します。脆弱性の重要度を変えると、脆弱性チェックではイメージに HIGH 脆弱性が含まれているかどうかによって、Cloud Build デプロイが合格または不合格になります。

  • トリガーを保存して、そのステータスが [有効] になっていることを確認します。

6. ビルドをキックオフするには、外観上の変更のための /src/static/js ファイルの更新など、コードベースに変更を加えます。変更が完了したら、その変更を GitHub リポジトリに push します。

7. Google Cloud コンソールで、Cloud Build サービスに移動し、[履歴] をクリックします。

8. このイメージに HIGH 脆弱性が含まれているため、ビルドは「ステップ 2: イメージ内の脆弱性をチェックする」で失敗し、Cloud Build はこのイメージを Artifact Registry に保存するための push を行いません。

https://storage.googleapis.com/gweb-cloudblog-publish/images/W_secure_CICD_pipeline.max-1500x1500.jpg

B. 2 つ目は、Binary Authorization ポリシー適用が原因の GKE へのイメージ デプロイの失敗 -

  1. このビルドのトリガー構成に戻って、"_SEVERITY" 環境変数の値を "HIGH" ではなく CRITICAL に変更します。

  2. ビルドをキックオフするには、外観上の変更のための /src/static/js ファイルの更新など、コードベースに変更を加えます。変更が完了したら、その変更を GitHub リポジトリに push します。

  3. Google Cloud コンソールで、Cloud Deploy パイプライン ci-cd-test に移動し、この最新リリースの結果をチェックします。

  4. Cloud Deploy パイプライン ページで、約 10 分後に、この Docker イメージの Kubernetes マニフェスト ファイルがタイムアウトするため、「テスト」と「ステージング」用のビルドは最終的に失敗します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/X_secure_CICD_pipeline.max-2200x2200.jpg

タイムアウト期間は短くできます。追加の詳細は、こちらで確認できます。

5. Google Cloud コンソールで、GKE ページに移動して、[ワークロード] をクリックします。ここで、失敗した「テスト」と「ステージング」の両方の GKE 環境へのイメージ デプロイを確認します。原因は、Binary Authorization ポリシー適用です。この「Vulnerable」Docker イメージはデプロイが承認されていません。

https://storage.googleapis.com/gweb-cloudblog-publish/images/Y_secure_CICD_pipeline.max-2200x2200.jpg

6. GKE ステージング環境のいずれかへのデプロイの失敗と平行して、Cloud Functions の関数 cd-deploy-notification は、パイプラインのログをチェックするための以下のメールを送信します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/S_secure_CICD_pipeline_1.max-2000x2000.jpg

7. メールで、デプロイログを確認するためにこちらをクリックすると、GKE へのリリース ロールアウトの失敗についての追加の詳細に関する Cloud Build 内のログファイルに移動します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/Z_secure_CICD_pipeline.max-2200x2200.jpg

結論とその他の参考資料

このブログ投稿では、Google Cloud の組み込みサービスを使用して、安全な CI / CD パイプラインを構築しました。

Binary Authorization やコンテナ イメージの脆弱性スキャンなどの Google Cloud の組み込みサービスを使用して、CI / CD パイプラインを保護する方法を学習しました。GKE クラスタにデプロイ可能な特定のイメージになんらかのコントロールを配置する 1 つの方法だけを確認しました。Binary Authorization はビルド検証も提供しています。Binary Authorization はビルド検証で証明書を使用して、イメージが特定のビルドシステムまたは Cloud Build などの継続的インテグレーション(CI)パイプラインによってビルドされたことを確認します。

加えて、Binary Authorization は、セキュリティ ポリシーによって定義された制約が原因でコンテナ イメージのデプロイがブロックされるすべてのイベントも監査ログに書き込みます。このようなログエントリに対するアラートを作成し、ブロックされたデプロイ イベントを適切なチームメンバーに通知できます。

最後に、CI / CD パイプラインの構築と保護に使用されるすべてのサービスはサーバーレスです。これにより、インフラストラクチャ全体を非常に簡単に数分以内でスピンアップできます。保守や管理の心配が要らないため、チームは、より迅速で、信頼性が高く、コスト効率の良い方法でソフトウェアの構築やリリースに集中できます。


- プリンシパル アーキテクト Anjali Khatri
- カスタマー エンジニア Nitin Vashishtha

投稿先