🔐

Google CloudのCloudBuild + KMSで機密ファイルを暗号化して管理する

2021/02/15に公開

ZennではAPIサーバーを動かすためにGCPを使っています。具体的にはCI/CDサービスのCloudBuildからAppEngineデプロイするようにしています。

その中で少しややこしいのが機密データを含むファイルの管理です。

GCPのプロジェクトの場合にはCloud Key Management System(KMS)というものを合わせて使うとCloudBuildのステップの中で暗号化したファイルを復元できます。

例えば、秘匿情報を含む.envというファイルがあるとして、GitHub等にはプッシュしたくないが、AppEngineで動かすアプリの中で読み込みたいというケースを考えてみます。

GCPではCloudBuild + KMSを使うことで実現が可能です。

大まかな流れ

  1. .gitignore.envを指定
  2. ローカルでKMSにより.envを暗号化(.env.encファイルが作成される)
  3. .env.encは普通にGitHubにプッシュする
  4. CloudBuildのステップの最初の方で.env.encを復号化して.envを復元する
  5. CloudBuildからAppEngineにデプロイ(.envを含めてデプロイ)

※ サービス間で連携するために、CloudBuildとAppEngine、KMSは同じGCPのプロジェクトで管理する必要があります。

事前準備

ローカルでCloudSDK(CLI)を使えるように

https://cloud.google.com/sdk/docs/install

gcloudコマンドを使ってローカルでファイルの暗号化を行います。

KMSを有効化

ダッシュボードからAPIを有効化する必要があります。

KMSのキーリングとキーを作成する

キーリングは複数のキーを束ねるもののようなイメージです。キーリングの中にキー(鍵)を作ることになります。

キーリングとキーの作成はgcloudコマンドからもできたと思いますが、ダッシュボードでの操作が十分に分かりやすかったです。手順はドキュメントに丁寧に説明されています。

https://cloud.google.com/kms/docs/creating-keys

ローカルで暗号化した.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の設定をしておきましょう。この手順もドキュメントに丁寧に書かれています。

https://cloud.google.com/build/docs/securing-builds/use-encrypted-secrets-credentials?hl=ja

CloudBuildのステップの中で.envを復号

KMSで暗号化したファイルの復号はgcloud kms decryptコマンドにより可能です。CloudBuildではgcr.io/cloud-builders/gcloudというイメージをnameに指定することでステップの中でgcloudコマンドを実行できます。

cloudbuild.yaml
# 暗号ファイルを復元 => ファイルとして配置
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の設定を行っておく必要があります

cloudbuild.yaml
# 暗号ファイルを復元 => ファイルとして配置
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