2022/4/22 追記
その後、Cloud BuildとSecret Managerとの連携が簡単に設定できるようになっていました:
Secret Manager のシークレットの使用 | Cloud Build のドキュメント | Google Cloud
availableSecrets
フィールドを使用すれば、Secret Manager シークレットの内容を環境変数に反映させることができます。
GitHub接続についてのドキュメントも availableSecrets
を利用する内容に更新されていました:
SSH 認証鍵を使用してビルドから GitHub にアクセスする | Cloud Build のドキュメント | Google Cloud
本記事のように gcloud
を使ったステップを入れるよりも、こちらの方法のほうがシンプルで良いでしょう。
2021/1/30 追記
本記事の公開時点では Cloud Build 公式ドキュメント "限定公開 GitHub リポジトリへのアクセス" の内容が Cloud KMS を利用したものになっていましたが、現在は本記事と同じく シークレットマネージャ を利用する内容に更新されています。 ぜひ本記事と併せて公式ドキュメントの内容もご確認ください。
背景
Cloud Build はGCP上でビルド処理を実行するためのサービスです。 主に CI/CD パイプラインを構築するために利用されます。
公式ドキュメント "限定公開 GitHub リポジトリへのアクセス" ではこのCloud BuildでGitHubのプライベートリポジトリにアクセスする方法が紹介されています。その内容は、あらかじめGitHubに接続するためのSSH秘密鍵を暗号化しておき、ビルドプロセスの中で Cloud KMS を使って秘密鍵を復号してSSH認証に使用するというものです。
この例は手動ビルドを実行する場合を想定しており、 ビルドトリガーを使う場合 は秘密鍵を使わず自動的にプライベートリポジトリにアクセスできるとしています。
しかし、例えば
- ビルド構成設定とアプリケーションのソースコードを別のリポジトリで管理したい場合
- ビルド時に複数のGitHubリポジトリからソースを取得したい場合
など、自動トリガーによって開始されたビルド中に他のGitHubプライベートリポジトリへアクセスしたい場合には、やはりSSH秘密鍵等の認証情報が必要になります。
このとき上の Cloud KMS による方法を使おうとすると、ソースに暗号化されたSSH秘密鍵を含める必要があります。しかし、暗号化されているとはいえソースに秘密鍵をコミットする運用は避けたいところです。
そこで、本記事では Cloud KMS に替えて シークレット マネージャー を使用して秘密鍵を取得し、それを使ってSSH認証を行うことを試みます。
シークレット マネージャーは 2020年3月11日に正式版がリリース されたばかりの新しいサービスで、秘密情報専用の管理機構を備えています。 これを利用すると任意の秘密情報を保存した上で Cloud IAM によるアクセス制御を行うことができるようになります。Cloud Buildの実行時にはIAMのサービスアカウントが与えられるので、そのサービスアカウントに対してアクセスを許可することによってビルド中に秘密情報を取得できるようになります。
事前準備
GitHub と GCP
- 2つの GitHub リポジトリ を用意します
- ソースリポジトリ
username/private-source-repo
- Cloud Build からアクセスしたい非公開リポジトリです。内容は何でも構いません。
- ビルド構成管理リポジトリ
username/cloudbuild-config-repo
- Cloud Build のビルド構成ファイル等を管理するためのリポジトリです。
- ソースリポジトリ
- GCPプロジェクト を1つ用意します(参考)
- プロジェクト名は任意です。ここでは
projectname
とします。 - このプロジェクトで Secret Manager API を有効化しておきます。
- プロジェクト名は任意です。ここでは
- ローカルマシンに gcloud コマンドラインツール をインストールしておきます
GCPプロジェクト名やGitHubユーザー名・リポジトリ名は任意です。 以下の例で必要な箇所については適当な名前で読み替えてください。
gcloud
の設定
ローカルマシンで以下のコマンドを実行し、ユーザー認証を行います
gcloud auth login
対象プロジェクトを projectname
に設定します
gcloud config set project projectname
デプロイキーの作成
以下の例ではGitHubプライベートリポジトリへアクセスする際に デプロイキー による認証を利用します。 なお本記事の内容はデプロイキーの代わりに適当な マシンユーザー アカウントのSSH鍵や Personal Access Token でアクセスする場合にも同様に適用することができます。
次のコマンドで秘密鍵 github_deploy_key
/ 公開鍵 github_deploy_key.pub
ペアを生成します:
ssh-keygen -f github_deploy_key
鍵ペアを作成したら、ブラウザでGitHubリポジトリ username/private-source-repo
の "Settings" ページを開き、公開鍵 github_deploy_key.pub
を Deploy Key として登録しておきます。
これで秘密鍵 github_deploy_key
による認証でプライベートリポジトリ username/private-source-repo
にアクセスできるようになります。
秘密鍵をシークレットとして保存
次のコマンドを実行して、作業ディレクトリにある秘密鍵ファイル github_deploy_key
の内容を シークレット マネージャー に保存します:
gcloud secrets create github_deploy_key --data-file=github_deploy_key
これによって github_deploy_key
という名前のシークレットが作成されます。
次のようにして保存された秘密鍵にアクセスできることを確認します:
gcloud secrets versions access --secret=github_deploy_key latest
シークレットの作成はGCPコンソールのウェブUI上でも可能ですが、Cloud Build では gcloud
を使ってアクセスすることになるので、あらかじめローカル環境で挙動を確認しておいたほうが良いでしょう。
アクセス権の設定
Cloud Build から保存されたシークレットの内容にアクセスできるように設定します。
Cloud IAM
でサービスアカウント [PROJECT_NUMBER]@cloudbuild.gserviceaccount.com
に対して Secret Manager のシークレット アクセサー の役割を与えます(参考: "サービス アカウントへの役割の付与")。このとき、 [PROJECT_NUMBER]
はプロジェクト projectname
のプロジェクト番号で置き換えます。
プロジェクト番号はGCPコンソールのダッシュボードで確認します(参考)。
このサービスアカウント [PROJECT_NUMBER]@cloudbuild.gserviceaccount.com
は Cloud Build を実行する際に使用される Google 管理サービス アカウント です。
ビルド構成管理リポジトリの作成
以下、ビルド構成管理リポジトリ username/cloudbuild-config-repo
に必要な内容を用意していきます。
このリポジトリには known_hosts
と cloudbuild.yaml
の2つのファイルを作成します。
known_hosts
ファイルを作成または更新
次のコマンドで known_hosts
ファイルを作成します:
ssh-keyscan -t rsa github.com > known_hosts
このファイルは github.com を既知のSSHホストとして確認するために使用されます。
ビルド構成ファイルを作成
Cloud Build のビルド構成ファイル cloudbuild.yaml
を以下のような内容で作成します:
steps:
# Secret Manager からデプロイキーをダウンロードする
- name: gcr.io/cloud-builders/gcloud
entrypoint: bash
args:
- -c
- gcloud secrets versions access --secret=github_deploy_key latest > /root/.ssh/id_rsa
volumes:
- name: ssh
path: /root/.ssh
# GitHubとのSSH接続のセットアップを行う
- name: gcr.io/cloud-builders/git
entrypoint: bash
args:
- -c
- |
chmod 600 /root/.ssh/id_rsa
cat <<EOF >/root/.ssh/config
Hostname github.com
IdentityFile /root/.ssh/id_rsa
EOF
mv known_hosts /root/.ssh/known_hosts
volumes:
- name: ssh
path: /root/.ssh
# GitHubリポジトリ username/private-source-repo を /src/private-source-repo にクローンする
- name: gcr.io/cloud-builders/git
args:
- clone
- [email protected]:username/private-source-repo
- /src/private-source-repo
volumes:
- name: ssh
path: /root/.ssh
- name: src
path: /src
#
# 以下、クローンしたソースを使用するステップが続く...
#
# 例として ls してみる
- name: alpine
args:
- ls
- /src/private-source-repo
volumes:
- name: src
path: /src
ポイントは最初のステップです:
# Secret Manager からデプロイキーをダウンロードする
- name: gcr.io/cloud-builders/gcloud
entrypoint: bash
args:
- -c
- gcloud secrets versions access --secret=github_deploy_key latest > /root/.ssh/id_rsa
volumes:
- name: ssh
path: /root/.ssh
このステップではシークレット マネージャーに保存されたシークレット github_deploy_key
にアクセスし、その内容を /root/.ssh/id_rsa
に書き込みます。
ここで gcloud
コンテナの ENTRYPOINT を bash
に変更することでリダイレクト >
による書き込みを可能にしています。
結局、このステップでは次のコマンドが実行されることになります:
bash -c 'gcloud secrets versions access --secret=github_deploy_key latest > /root/.ssh/id_rsa'
また、作業ディレクトリ (/workspace
) 以外の場所にファイルを作成するときは volumes
を指定して永続化することも必要です(この例では /root/.ssh
と /src
)。
以上のように known_hosts
と cloudbuild.yaml
を作成したら、リポジトリ username/cloudbuild-config-repo
にコミットしておきます。
ビルドトリガーの設定
GCPコンソールの "ビルドトリガー" ページ を開き、次のような設定でビルドトリガーを作成します:
- GitHubリポジトリ
username/cloudbuild-config-repo
を Cloud Source Repositories にミラーリングしてビルドソースとする - master ブランチへのプッシュなど適当なトリガー条件を設定
- ビルド構成ファイルとして
cloudbuild.yaml
を使用する
ビルドトリガーの作成手順はドキュメント "ビルドトリガーを使用したビルドの自動化" に書かれているとおりです。
テスト
リポジトリ username/cloudbuild-config-repo
に適当なコミットを push するか、手動でトリガーを実行するとビルドが開始されます。
実行されたビルドの状態やログは "ビルド履歴" のページ から確認することができます。
この例ではデモとして ls
コマンドで /src/private-source-repo
ディレクトリ内のファイル名をログに出力しています。思惑通りソースリポジトリがクローンできていればその内容がログ出力に反映されるはずです。
まとめ
Cloud Build の自動トリガーされたビルドで、ビルドソース以外のGitHubプライベートリポジトリにアクセスするため、以下のことを行いました:
- シークレット マネージャー にGitHub接続用のSSH秘密鍵を保存しました
- Cloud Build から シークレット マネージャー にアクセスできるよう Cloud IAM の設定を行いました
- Cloud Build のビルドプロセス内で シークレット マネージャー にアクセスしてSSH秘密鍵をダウンロードしました
- ダウンロードしたSSH秘密鍵を使って Cloud Build から GitHub に接続しました
この例では認証情報としてSSH秘密鍵を使ってGitHubのプライベートリポジトリにアクセスしましたが、 他にもAWSアクセスキーを使って非公開S3バケットにアクセスしたり、パスワードを使ってデータベースにアクセスしたりと、様々なケースに応用できるはずです。