Cloud Buildを使ってアプリをGAEにデプロイする際に機密データを渡したい

# はじめに
[前回の記事](https://qiita.com/items/d9ef6dceac1d34a46564/) では Cloud Build を使って Springbootアプリ を GAE にデプロイしてみました。

今回は前回と同様 Cloud Build を使いつつ、DBパスワード や APIキー など
リポジトリにそのまま保存したくない機密データを [暗号化して保護してみます](https://cloud.google.com/cloud-build/docs/securing-builds/use-encrypted-secrets-credentials?hl=ja)。

# 今回やることの概要
事前に機密データを [Cloud KMS の対称鍵](https://cloud.google.com/kms/docs/creating-keys?hl=ja) で [暗号化しておき](https://cloud.google.com/kms/docs/encrypt-decrypt?hl=ja#encrypt)、Cloud Build の
途中のステップでそれを [復号して](https://cloud.google.com/kms/docs/encrypt-decrypt?hl=ja#decrypt) アプリに渡します。

# 事前準備
下記の手順で対称鍵を作成し、Cloud Build から使用できるようにしておきます。

- Google Cloud KMS API を有効にする
- キーリングを作成する
- 対称鍵を作成する
- Cloud Build のサービスアカウントに対称鍵へのアクセス権を付与する

### Google Cloud KMS API を有効にする
次の通りWEBコンソールでポチポチするか、またはCUIで行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26808/49b48d06-3133-2fdb-5816-76c70614e2b8.png)
または

```
> gcloud services enable cloudkms.googleapis.com
Operation "operations/acf.0186f101-c31d-4fb1-bd09-387cc9a35c0e" finished successfully.
```
### キーリングを作成する
[公式のここ](https://cloud.google.com/kms/docs/object-hierarchy?hl=ja) によると、鍵はいずれかのキーリングに含める必要があります。
[ここを参考に](https://cloud.google.com/kms/docs/creating-keys?hl=ja) キーリングを作成します。

```
> gcloud kms keyrings create wai-no-keyring --location=global
```

### 対称鍵を作成する
対称鍵も作成します。

```
> gcloud kms keys create wai-no-key --location=global --keyring=wai-no-keyring --purpose=encryption
```
以上で鍵の作成まで出来ました。
結果をWEBコンソールで確認すると次のような感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26808/ea0cfb78-81e4-7a72-9386-2e2ac411d497.png)

### Cloud Build サービス アカウントに対称鍵へのアクセス権を付与する
[公式のここ](https://cloud.google.com/cloud-build/docs/securing-builds/use-encrypted-secrets-credentials?hl=ja#grant_the_service_account_access_to_the_cryptokey) を参考に Cloud Build から作成した鍵にアクセスできるようにします。

```
> gcloud kms keys add-iam-policy-binding wai-no-key --location=global --keyring=wai-no-keyring --member=serviceAccount:70479915102@cloudbuild.gserviceaccount.com --role=roles/cloudkms.cryptoKeyDecrypter
Updated IAM policy for key [wai-no-key].
bindings:
- members:
  - serviceAccount:70479915102@cloudbuild.gserviceaccount.com
  role: roles/cloudkms.cryptoKeyDecrypter
etag: BwWQCawaIKM=
version: 1
```

以上で事前準備は完了です。

# 暗号化する
今回はSpring前提ということで、保護したい情報を application-prod.yml に記載して、
このファイルを暗号化することにします。

次のような手順になります。

- application-prod.yml を作成する
- application-prod.yml を暗号化して application-prod.yml.enc を作成する
- 本番環境では application-prod.yml を参照するよう指定する

### application-prod.yml を作成する
application.yml をコピって適当に作ります。

```yaml:application-prod.yml
certain-setting-value: わいの恥ずかしいひみつ
```

### application-prod.yml を暗号化して application-prod.yml.enc を作成する
[公式のここ](https://cloud.google.com/kms/docs/encrypt-decrypt?hl=ja) を参考に暗号化します。

```
> gcloud kms encrypt --location global --keyring wai-no-keyring --key wai-no-key --plaintext-file application-prod.yml --ciphertext-file application-prod.yml.enc
```
上記コマンドで生成された .encファイル のみを src\main\resources に追加します。

### 本番で application-prod.yml を参照するよう指定する
app.yaml に次のように [環境変数を追加](https://cloud.google.com/appengine/docs/flexible/custom-runtimes/configuring-your-app-with-app-yaml#defining_environment_variables) して、本番では application-prod.yml を参照するようにします。

```yaml:src\main\appengine\app.yaml（抜粋）
env_variables:
  SPRING_PROFILES_ACTIVE: 'prod'
```

以上で暗号化は完了です。

# 復号する処理を仕込む
公式の [こことか](https://cloud.google.com/kms/docs/encrypt-decrypt?hl=ja#decrypt) [こことか](https://cloud.google.com/cloud-build/docs/securing-builds/use-encrypted-secrets-credentials?hl=ja) を参考に前回作った cloudbuild.yaml に復号処理を追記します。
次の通り。

```yaml:cloudbuild.yaml
steps:
#--------------------------------------------------------------------------------
# (1/3) build と deploy に使うカスタムイメージを作成 (Including gcloud, jdk, maven)
#--------------------------------------------------------------------------------
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '--tag=gcr.io/$PROJECT_ID/gcloud-maven', '-f', 'Dockerfile.gcloud-maven', '.']

#--------------------------------------------------------------------------------
# (2/3) application-prod.yml を復号
#--------------------------------------------------------------------------------
- name: 'gcr.io/$PROJECT_ID/gcloud-maven'
  args:
  - gcloud
  - kms
  - decrypt
  - --ciphertext-file=src/main/resources/application-prod.yml.enc
  - --plaintext-file=src/main/resources/application-prod.yml
  - --location=global
  - --keyring=wai-no-keyring
  - --key=wai-no-key

#--------------------------------------------------------------------------------
# (3/3) カスタムイメージで build と deploy を行う
#--------------------------------------------------------------------------------
- name: 'gcr.io/$PROJECT_ID/gcloud-maven'
  args: ['mvn', 'clean', 'package', 'appengine:deploy']

images: ['gcr.io/$PROJECT_ID/gcloud-maven']
timeout: 1200s
```

以上でデプロイ出来るようになりました。

# デプロイして動作確認する
前回の記事と同じコマンドでデプロイします。
次の通り。

```
> gcloud builds submit
Creating temporary tarball archive of 10 file(s) totalling 4.5 KiB before compression.
Some files were not included in the source upload.
(中略)
Step #2: [INFO] GCLOUD: .................................done.
Step #2: [INFO] GCLOUD: Deployed service [default] to [https://springboot-webapp-project.appspot.com]
Step #2: [INFO] GCLOUD:
Step #2: [INFO] GCLOUD: You can stream logs from the command line by running:
Step #2: [INFO] GCLOUD:   $ gcloud app logs tail -s default
Step #2: [INFO] GCLOUD:
Step #2: [INFO] GCLOUD: To view your application in the web browser run:
Step #2: [INFO] GCLOUD:   $ gcloud app browse --project=springboot-webapp-project
Step #2: [INFO] ------------------------------------------------------------------------
Step #2: [INFO] BUILD SUCCESS
Step #2: [INFO] ------------------------------------------------------------------------
Step #2: [INFO] Total time: 06:16 min
Step #2: [INFO] Finished at: 2019-08-14T03:01:35+00:00
Step #2: [INFO] Final Memory: 34M/101M
Step #2: [INFO] ------------------------------------------------------------------------
Finished Step #2
(後略)
```

デプロイが成功したらブラウザで見てみます。
次の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26808/b49cd98f-6a80-4bb2-09ee-82aaf6e95885.png)

以上で確認できました。

# さいごに
今回は暗号化した機密ファイルを [リポジトリで管理する](https://cloud.google.com/cloud-build/docs/securing-builds/use-encrypted-secrets-credentials?hl=ja#storing_the_encrypted_file) イメージで作りましたが、
代わりに Cloud Storage に保存しておいて取得する作りにもできそうな気がします。

以上です。