[GCP] berglasを使って機密情報を安全にアプリケーションに受け渡す

はじめに

アプリケーションには、DBの認証情報やAPIキーなど、リポジトリにはコミットするべきではない機密情報がつきものですよね。AWSでは、情報を暗号化/復号化するための鍵を管理するAWS KMSというサービスと、鍵を使って情報を管理するためのAWS Systems Manager パラメータストアやAWS Secrets Managerというサービスが統合されており、それらを使うことで機密情報を管理することができ、他のAWSのサービスとも統合されているのでアプリケーションへの受け渡しも容易です。

GCPでは、Cloud KMSという鍵を管理するためのサービスはありますが、鍵を使って情報を管理するためのサービスはないため、GCPが開発しているOSSのBerglasというツールか、HashiCorp社のOSSであるVaultを使って管理することが推奨されています。

本記事ではBerglasについて紹介します。

Berglasとは

BerglasはGoで作られたCLIツールです。ざっくり説明してしまうと、鍵の管理にCloud KMSを使い、暗号化した情報の管理にCloud Storageを使い、それらの操作をいい感じにラップしてくれているツールです。Vaultと違って管理するサーバが無いので、容易に使うことができます。監査ログとしてはCloud KMSやCloud Storageの監査ログが使えますが、それ以上の管理機能はないので、より厳密な管理を求められる場合はVaultを使うという棲み分けになるかと思います。

セットアップ

手元の環境にCloud SDKはインストールされているものとします。

berglasはバイナリをダウンロードするか、Macであればbrewでインストールできます。

$ brew install berglas

必要なサービスを有効化します。

$ gcloud services enable --project ${PROJECT_ID} \
  cloudkms.googleapis.com \
  storage-api.googleapis.com \
  storage-component.googleapis.com

bootstrapコマンドでCloud KMSにKeyRingとKeyが、Cloud Storageにバケットが作成されます。

$ berglas bootstrap --project $PROJECT_ID --bucket $BUCKET_ID

値の登録・取得

create コマンド、登録したい値をKeyとValueのペアで登録します。

$ berglas create ${BUCKET_ID}/${Key} ${Value} \
    --key projects/${PROJECT_ID}/locations/global/keyRings/berglas/cryptoKeys/berglas-key

grant コマンドで、ユーザやサービスアカウントにアクセス権を付与します。

$ berglas grant ${BUCKET_ID}/${Key} --member user:${UserAccount}

Google App Engineの場合は、GAEのサービスアカウントを指定します。

$ berglas grant ${BUCKET_ID}/${Key} --member serviceAccount:${AppName}@appspot.gserviceaccount.com

access コマンドで、値を取得します。

$ berglas access ${BUCKET_ID}/${Key}

Google App Engineで利用する

アプリケーションで利用する場合は、berglas exec コマンドを利用すると値を復号化して環境変数にセットしてくれます。このコマンドは、特定の値がセットされている環境変数に復号化した値をセットして、子プロセスに引き継ぐことができるようになっています。

READMEのIntegrationsでは、Google App Engine(Standard環境)で利用する場合は、goランタイムのみで利用できると書かれていますが、Cloud Buildと組み合わせることでどのランタイムでも利用することができます

まず、Cloud Buildでプロジェクトの直下にberglasのバイナリをダウンロードして配置し、実行権限を付与します。

steps:
  - name: gcr.io/cloud-builders/curl
    args: 
      - https://storage.googleapis.com/berglas/master/linux_amd64/berglas
      - --output
      - berglas
  - name: ubuntu
    args: 
      - chmod
      - "777"
      - berglas
  - name: gcr.io/cloud-builders/gcloud
    args: 
      - app
      - deploy
      - app.yaml

そして、app.yaml の entrypointberglas exec を実行してアプリケーションプロセスを起動します。

以下はNode10のランタイムの例です。DBのユーザ名とパスワードはberglasで予め登録されているものとします。 app.yaml の env_variables に以下のように berglas://{BUCKET_ID}/{KEY} を指定します。そうすると berglas exec が実行されたときにこの値が復号化された値に置き換わり、 npm start のプロセスへ引き継がれます。

runtime: nodejs10
entrypoint: ./berglas exec -- npm start
env_variables:
  NODE_ENV: 'production'
  DB_USERNAME: berglas://{BUCKET_ID}/db-username
  DB_PASSWORD: berglas://{BUCKET_ID}/db-password

【注意】プロジェクトのルートにcloudbuild.yamlとapp.yamlの両方があると、GAEのビルド時にエラーになります。GAEのビルドにもCloud Buildが使われるため、内部的にcloudbuild.yamlを配置しようとするが既にcloudbuild.yamlがあるので配置できない、ということだと思います。cloudbuild.yamlの名前を変えることで解決できます。