Cloud KMSでID/Passwordを暗号化し、Cloud Buildで利用する

GCPには Cloud KMS(Cloud Key Management Service) というものがあり、暗号鍵を便利に管理する仕組みがあります。

アプリケーション内に認証情報などのような機密データを含めたい場合、Cloud KMS を利用することで安全に運用することができます。

Cloud KMS のさわりを確認してみる

Cloud KMSがどのようなことができるか gcloud コマンドを利用して試してみましょう

事前準備

Cloud KMSを利用する場合、KeyRingsとKeyを作成する必要があります。

KeyRingsはその名前の通り、Key(鍵)を束ねておく概念で、Keyは暗号化/復号化に利用する鍵となります。

厳密には プロジェクト → ロケーション → キーリング → 鍵 → 鍵バージョン という階層化された構造で管理されます。

プロジェクトはGCPのプロジェクトそのもの、ロケーションはリージョン(マルチリージョン)を指定でき、 global とすることでいずれのリージョンからも利用できる鍵となります。

(global指定した鍵は一部制約があります)

KeyRingsを作成する

以下のコマンドで作成します

gcloud --project ${PROJECT_ID} kms keyrings create ${KEYRING_NAME} --location global

KeyRings配下にKeyを作成する

以下のコマンドで作成します

gcloud --project ${PROJECT_ID} kms keys create ${KEY_NAME} --location global --keyring ${KEYRING_NAME} --purpose encryption

作成した鍵が登録されているか確認してみます

gcloud --project ${PROJECT_ID} kms keys list --location global --keyring ${KEYRING_NAME}

作成した鍵のNAMEが見えればOKです。

ファイルを暗号化してみる

コマンドを実行するディレクトリに適当な内容のtextファイルを作成します。(base.txt とします)

実際に利用するケースとしては、GCPのサービスアカウントのjsonファイルなどの暗号化に利用することになると思います。

以下のコマンドで暗号化を実行してみます

gcloud --project ${PROJECT_ID} kms encrypt \
--plaintext-file=base.txt \
--ciphertext-file=base.txt.enc \
--location=global \
--keyring=${KEYRING_NAME) \
--key=${KEY_NAME}

base.txtファイルを base.txt.enc というファイル名のファイルに暗号化し出力されます。

gitなどで機密情報を格納したい場合にはこの状態のファイルをgitで管理します。

ファイルを復号化する

先程の暗号化したファイルを以下のコマンドで復号化できます

gcloud --project ${PROJECT_ID} kms decrypt \
--ciphertext-file=base.txt.enc \
--plaintext-file=base.txt.dec \
--location=global \
--keyring=${KEYRING_NAME} \
--key=${KEY_NAME}

base.txt.enc ファイルが base.txt.dec ファイルとして復号化し出力されます。このファイルは一番最初に用意した base.txt ファイルと同一の内容のものになります。

ファイルではなくインラインで暗号化する

環境変数の値や、アプリケーションに埋め込みたいパラメータをインラインで暗号化するには以下のように実行します

echo -n ${SAMPLE_TEXT} | \
gcloud --project ${PROJECT_ID} kms encrypt \
--plaintext-file=- \
--ciphertext-file=- \
--location=global \
--keyring=${KEYRING_NAME} \
--key=${KEY_NAME} | base64

*追記* echo コマンドの際に -n オプションを付けないとうまくいかないことがあるようです。ご注意。

SAMPLE_TEXTという環境変数を暗号化したものをbase64化した文字列を得ることができます。

後述しますが、Cloud Buildでパラメータ(例えばID/Passwordのようなもの)をアプリケーションに含めたい場合などに利用できます。

Cloud Buildで暗号化したファイルを復号化して利用したい

試しにCloud Buildで暗号化したファイルを復号化し、出力されたファイルをcatしてみます。

catコンテナのDockerfileは以下のようになります。

FROM alpine
ENTRYPOINT ["cat"]

試したい場合には事前に gcloud builds submit --project ${PROJECT_ID} --tag gcr.io/${PROJECT_ID}/cat のようなかたちでcatコンテナをbuildしてgcrに登録しておくと以下のyamlを試すことができます。

steps:
# 暗号化したファイルを Cloud Build 上で復号化してファイルとして取得する
- name: gcr.io/cloud-builders/gcloud
args:
- kms
- decrypt
- --ciphertext-file=base.txt.enc
- --plaintext-file=/workspace/base.txt
- --location=global
- --keyring={{KEYRING_NAME}}
- --key={{KEY_NAME}}
id: 'decode'
- name: gcr.io/$PROJECT_ID/cat
args:
- /workspace/base.txt
id: 'echo'

上記のようなyamlファイルを用意し、同一のディレクトリに先程作成した base.txt.enc を配置します

gcloud --project ${PROJECT_ID} builds submit --config=cloudbuild_01.yaml ./

上記のようなコマンドで実行できます。
Cloud Buildのワークディレクトリは /workspace/ になるので、その配下に base.txt として出力し、そのファイルをcatコンテナでログ出力しています。

例えば、このファイルがGCPのサービスアカウントのjsonである場合には gcloud auth activate-service-account --key-file /workspace/base.txt のような方法で後続のstepでgcloudコマンドを認証することができます。

Cloud Buildで暗号化したパラメータを環境変数として利用したい

Cloud Buildのステップ内でなにかID/Passwordのようなgitリポジトリに平文で登録したくないような情報は環境変数として利用することができます。

envコンテナのDockerfileは以下のようになります。

FROM alpine
ENTRYPOINT ["env"]

試したい場合には事前に gcloud builds submit --project ${PROJECT_ID} --tag gcr.io/${PROJECT_ID}/env のようなかたちでenvコンテナをbuildしてgcrに登録しておくと以下のyamlを試すことができます。

steps:
# 暗号化した変数を Cloud Build 上で復号化して環境変数として取得する
- name: gcr.io/$PROJECT_ID/env
args:
secretEnv: ['WORD']
secrets:
- kmsKeyName: projects/{{PROJECT_ID}}/locations/global/keyRings/{{KEYRING_NAME}}/cryptoKeys/{{KEY_NAME}}
secretEnv:
WORD: "{{インラインで暗号化した文字列}}"

上記のようなyamlファイルを用意し、

gcloud --project ${PROJECT_ID} builds submit --config=cloudbuild_02.yaml ./

のようなコマンドで実行することができます。

ログに環境変数が出力され、復号化された文字列が出力されていると思います。

注意点としては、cloudbuild.yamlのsecrets > kmsKeyName のフィールドは $PROJECT_ID などのようなCloud Buildの変数が展開されないようです。 
invalid argumentのようなエラーが出る場合にはその辺りを見直してみると良いと思います。