Secret Manager 利用の基本プラクティス

これは [Google Cloud + Gaming Advent Calendar 2020](https://qiita.com/advent-calendar/2020/gcp-gaming) の 15 日目の記事です。

こんにちは、KLab の motoda-k です。
今年は Google Cloud 様の "Expert of GCP for Gaming Japan"(通称 E.G.G.) というプログラムの第 2 期生として参加させていただき、つい先日 無事に [Google Cloud Professional Cloud Architect](https://cloud.google.com/certification/cloud-architect?hl=ja) 認定試験に合格することができホッとしているところです。(E.G.G. については [14 日目の記事](https://qiita.com/gutio/items/fbdc0600567e16877de3)を参考にされてください)

## はじめに

SHOTGUN という SaaS のクリエイティブ成果物の制作管理ツールがあり、KLab でも活用しています。

この SHOTGUN、プロジェクト毎のカスタマイズも柔軟に設定することが可能なのですが、それだけでは足りないという場合に拡張機能を作成することができます。
この拡張機能の作成にあたり [SHOTGUN の API](<https://support.shotgunsoftware.com/hc/ja/articles/219031398-Shotgun-%E3%81%AE-API>) を使用するのですが、その際に必要なアプリケーションキー(=シークレット) をどう扱うかという点についてアイデアを説明したいと思います。


## シークレットを取り扱ういくつかの方法
シークレット(秘匿情報)を扱う方法についてざっと思いつくものを挙げると以下があります。

-   コードに直書き
    -   コードリポジトリを参照できる人はだれでも参照できてしまう
-   設定ファイルに記載
    -   具体的な値が書かれた設定ファイルをリポジトリで管理している場合はコード直書きと同じ
    -   実行環境毎に配置する場合でも、それをどのように管理するかが課題
-   環境変数に設定
    -   実行環境によっては内容が表に出るため不適
-   GCS に置く
    -   適切な参照権限をつければアリかも..

そして、Secret Manager の利用が考えられます。

[Secret Manager](https://cloud.google.com/secret-manager) は、API キー、パスワード、証明書、その他の機密データを保存するための安全で便利なストレージ システムです。
Secret Manager は、Google Cloud で使用するすべてのシークレットを 1 か所で管理、アクセス、監査するための信頼できる単一のソースとなります。


ただし、アプリケーションが取得したシークレットをどこかに出力すると台無しです。
ではどうすればよいか。



## クラウド移行に伴うパラダイムシフト

旧来の開発スタイルの一例としては

-   ローカルで VM を利用した開発環境を作成して開発・テスト
-   オンプレの検収・本番環境に手動でデプロイ

という流れで、開発者が本番環境に入ってオペレーションするのはごく普通のことでした。(少なくとも私の経験上では)

それが、GCP のようなクラウドの活用に移行するにつれ、各所で意識の転換が必要となってきます。
デプロイや{開発・検収・本番}環境に対する考え方もその一つで、**開発者は本番環境を触れるべきではないし、本番環境作業者はコードに手を入れられるべきではない** という GCP のプラクティスがあります。

最近まで私はこの意識が欠けていたため、GCP の Secret Manager のメリットがあまり見えていませんでした。
(Secret Manager にシークレットを格納しても、開発者がその気になれば参照できるじゃんってことで)

このプラクティスに従うならば、次のようなシナリオ・仕組みが考えられ、適切にシークレットを管理できそうです。(状況によって細部は変わってくると思うのであくまで一例です)


## 登場人物

-   シークレット発行者: SHOTGUN アプリケーションキーの発行者
-   本番 GCP 環境作業者
-   開発者: API アクセスするアプリケーション(拡張機能)の開発者

アプリケーション: SHOTGUN へ API アクセスして処理をする実装


## シナリオ

### 前提

-   本番(prod) 用の GCP プロジェクトが用意されていること
-   SHOTGUN に開発用プロジェクトと本番用プロジェクトが用意されており、拡張機能も開発用・本番用で登録されていること

### [シークレット発行者]
  API アクセスできるアプリケーションキー(dev, prod)の発行を行い、[本番 GCP 環境作業者] に共有

### [本番 GCP 環境作業者]
  Service Account (SA) を作成 (for dev, prod)
  アプリケーションキー情報をシークレットマネージャーに登録し、SA に roles/secretmanager.secretAccessor の権限を付与
  デプロイ先(Cloud Functions や Cloud Run など)の実行 SA として設定
  また、dev 用の SA についてはクレデンシャルファイル(json)を生成し、[開発者] へ共有

### [開発者]
  dev の SA を使って実装・デバッグし、完成したらリポジトリへ PR

### [本番 GCP 環境管理者]
  PR をトークン流出の観点からレビューし、問題なければ approve

その後、PR がマージされたら(GitHub Actions, Cloud Build, etc により)自動デプロイ
(開発者は直接デプロイする権限はない)

## サンプル
SA の作成とシークレットの格納、そしてその参照権限をつけるサンプルは次のとおり

```shell
GCP_PROJECT=$(gcloud config get-value project)
SA_NAME="secret-accessor-sa"
SA=${SA_NAME}@${GCP_PROJECT}.iam.gserviceaccount.com
DISPLAY_NAME=""
SECRET_NAME="my-secret"

# SA 作成
gcloud iam service-accounts create ${SA_NAME} --display-name "${DISPLAY_NAME}"

# シークレットマネージャーにシークレット登録
printf "s3cr3t" | gcloud secrets create "${SECRET_NAME}" --data-file=-

# SA にシークレット読み取り権限を付与
gcloud secrets add-iam-policy-binding "${SECRET_NAME}" \
  --member='serviceAccount:${SA}' \
  --role='roles/secretmanager.secretAccessor'
```

## おわりに
簡単な紹介でしたがいかがだったでしょうか。
今回の記事がどなたかの参考になれば幸いです。


なお、今回のトピックに少し関連した話で、私は GCP の IAM まわりの理解にモヤっとしていたのですが、その一因が、
"すべての権限まわりの情報が IAM に集約されておらず、各 GCP プロダクト側のポリシーも参照する必要がある" 事だ
ということに気づきました。

つまりたとえば、IAM のポリシーを一覧しようとして `gcloud projects get-iam-policy <project_name>` とやるのですが、
これでは Secret Manager のシークレットへの参照権限を持つ SA はリストされず、`gcloud secrets get-iam-policy <secret_name>` のように
個別のプロダクトについて get-iam-policy とやる必要があるわけです。
この辺り 私の理解不足もあるかもしれませんが、すべての権限情報を一覧するような方法があれば知りたいところです。