Google CloudのCloudBuild + KMSで機密ファイルを暗号化して管理する
ZennではAPIサーバーを動かすためにGCPを使っています。具体的にはCI/CDサービスのCloudBuildからAppEngineデプロイするようにしています。
その中で少しややこしいのが機密データを含むファイルの管理です。
GCPのプロジェクトの場合にはCloud Key Management System(KMS)というものを合わせて使うとCloudBuildのステップの中で暗号化したファイルを復元できます。
例えば、秘匿情報を含む.env
というファイルがあるとして、GitHub等にはプッシュしたくないが、AppEngineで動かすアプリの中で読み込みたいというケースを考えてみます。
GCPではCloudBuild + KMSを使うことで実現が可能です。
大まかな流れ
-
.gitignore
に.env
を指定 - ローカルでKMSにより
.env
を暗号化(.env.enc
ファイルが作成される) -
.env.enc
は普通にGitHubにプッシュする - CloudBuildのステップの最初の方で
.env.enc
を復号化して.env
を復元する - CloudBuildからAppEngineにデプロイ(
.env
を含めてデプロイ)
※ サービス間で連携するために、CloudBuildとAppEngine、KMSは同じGCPのプロジェクトで管理する必要があります。
事前準備
ローカルでCloudSDK(CLI)を使えるように
gcloud
コマンドを使ってローカルでファイルの暗号化を行います。
KMSを有効化
ダッシュボードからAPIを有効化する必要があります。
KMSのキーリングとキーを作成する
キーリングは複数のキーを束ねるもののようなイメージです。キーリングの中にキー(鍵)を作ることになります。
キーリングとキーの作成はgcloud
コマンドからもできたと思いますが、ダッシュボードでの操作が十分に分かりやすかったです。手順はドキュメントに丁寧に説明されています。
.env.enc
を生成する
ローカルで暗号化したgcloud kms encrypt
コマンドを使うことでローカルで暗号化ができます。具体的には以下のようなコマンドを実行します。
gcloud kms encrypt \
--project プロジェクト名 \
--plaintext-file=暗号化するファイル名 \
--ciphertext-file=暗号化後のファイル名 \
--location=global \
--keyring=キーリング名 \
--key=キー名
.env
ファイルを暗号化して.env.enc
を生成する場合には以下のようになります。
gcloud kms encrypt \
--project プロジェクト名 \
--plaintext-file=.env \
--ciphertext-file=.env.enc \
--location=global \
--keyring=キーリング名 \
--key=キー名
.env
はそのまま残るので忘れずに.gitignore
しておきましょう。暗号化された.env.enc
だけをgit管理するイメージですね。
CloudBuildがKMSのキーリング・キーにアクセスできるように
CloudBuildがKMSのキーリングとキーにアクセスできるようにIAMの設定をしておきましょう。この手順もドキュメントに丁寧に書かれています。
.env
を復号
CloudBuildのステップの中でKMSで暗号化したファイルの復号はgcloud kms decrypt
コマンドにより可能です。CloudBuildではgcr.io/cloud-builders/gcloud
というイメージをname
に指定することでステップの中でgcloud
コマンドを実行できます。
# 暗号ファイルを復元 => ファイルとして配置
steps:
# .env.enc から .env を復元
- name: gcr.io/cloud-builders/gcloud
args:
[
"kms",
"decrypt",
"--ciphertext-file=.env.enc",
"--plaintext-file=.env",
"--location=global",
"--keyring=キーリングの名前",
"--key=キーの名前",
]
これをCloudBuildのステップの最初の方で行うことで、その後の処理で.env
にアクセスできるようになります。
例えばAppEngineにデプロイするなら以下のような形になります。 ※ CloudBuildからAppEngineにアクセスできるようにIAMの設定を行っておく必要があります
# 暗号ファイルを復元 => ファイルとして配置
steps:
# .env.enc から .env を復元
- name: gcr.io/cloud-builders/gcloud
args:
[
"kms",
"decrypt",
"--ciphertext-file=.env.enc",
"--plaintext-file=.env",
"--location=global",
"--keyring=キーリングの名前",
"--key=キーの名前",
]
- name: gcr.io/cloud-builders/gcloud
args: ["app", "deploy", "app.yml"]
これで.env
が含まれた状態でAppEngineへとデプロイされるため、アプリ内で.env
へアクセスすることが可能になります。
例としてAppEngineを挙げましたが、他のGCPサービスでも同じような形が取れると思います。
Discussion