cloud functionにsecret managerをmountしてみた。

#概要
いままでcloud functionでsecret managerに保存したものを使うときは「google-cloud/secret-manager」を使ってアクセスしていましたが、新機能はsecret managerのsecretを環境変数として使ったりファイルとしてmountしたりできるようになりました。

公式資料に環境変数として使う例があるので、こちらでは割愛します。
https://cloud.google.com/blog/ja/products/serverless/cloud-functions-integrates-with-google-secret-manager

簡単に差分を説明してみると、
環境変数として使う：指定versionをlatestにしても、インスタンス起動時(deployするとき？)のsecret値が使われて、その後secret managerで値を更新してもdeployしなおさない限り反映されない
ファイルと同じ扱いでmount：実行するたびにsecret managerより指定versionのものをとってくるのでlatestにすれば常に最新のを使える

公式マニュアルを読んでもあまりSECRET_FILE_PATHを何を入れればいいかわからなかったので、テストログとして書かせていただきます。

#事前準備
+ google cloud platformにprojectがあって、deploy等の操作がvs codeからでも許可されてある
+ 対象cloud functionと同じprojectにあるsecret managerにmytokenとmycredentialという2 secretを作る
+ 対象cloud functionにsecret managerへのアクセス権限がある(詳細はhttps://cloud.google.com/functions/docs/configuring/secrets#grant-access
を参照してください。)

★まだbeta機能なので、「gcloud functions deploy」では使えなくて、「gcloud beta functions deploy」で行います。

# 今回の使用環境
+ runtime: nodejs14
+ function_name: test
+ トリガータイプ：http
+ vs codeのterminalよりdeploy
+ Cloud SDK version：356（更新前の347は、該当コマンドがないって怒られました。）

#本文
GCPのConsoleからでも設定できますが、ここはVS codeよりdeployを行うときの簡易例を紹介します。

まず、secret managerのデータをmountするってどういう意味かというと、「ファイルと同じ感じで読み込めるようにsecret managerの指定するデータをcloud functionからアクセスできるような仕組みだ。」と認識しています。

公式マニュアルの引数説明
「SECRET_FILE_PATH: シークレットのフルパス。たとえば、/etc/secrets/primary/latest の場合、/etc/secrets/primary/ はマウントパス、/latest/ はシークレットのパスです。マウントパスとシークレットのパスを別々に指定することもできます。」

そして

```
--set-secrets 'SECRET_FILE_PATH=SECRET:VERSION'
もしくは
--set-secrets 'MOUNT_PATH:SECRET_PATH=SECRET:VERSION'
```
を参考にしました。
secret managerにあるmytokenとmycredentialをアクセスしたい場合、
deployコマンドが

```
gcloud beta functions deploy test --runtime nodejs14 --trigger-http --set-secrets /token:latest=mytoken:latest,/credentials:latest=mycredential:latest
```
になります。

SECRET_FILE_PATHが読み込む時に使いたいパスになります。
/token:latest=mytoken:latestの部分を「/token/latest=mytoken:latest」にしても大丈夫です。

deploy時は下記のようなものが表示されます。

```
secretVolumes:
- mountPath: /token
  projectId: (セキュリティーにより削除)
  secret: mytoken
  versions:
  - path: /latest
    version: latest
- mountPath: /credentials
  projectId: (セキュリティーにより削除)
  secret: mycredential
  versions:
  - path: /latest
    version: latest
```

上記の例で実際の読み込み部分はこういう感じになります。

```
const fs = require('fs')
const contentCredentials = fs.readFileSync('/credentials/latest', "utf8");
```
contentCredentialsの中身は下記secret manager clientより取ったものと同じになります。

```
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const client = new SecretManagerServiceClient();
const versionCredentials = client.accessSecretVersion({
  name: credentials
})
const contentCredentials = versionCredentials.payload.data.toString('utf8')
```
#感想
+ 環境変数と同じようにファイルにまとめてコマンドに入れることができないのでdeployコマンドが長くてやや不便
+ mountしてみたところ、clientからの取得より早くなった気がしつつ、もうちょっと様子見しないと何も言えない
+ 公式マニュアルを読んだところ、deployコマンドの--set-secrets部分にsingle quoteをいれがち注意。([stack overflow](https://stackoverflow.com/questions/68977303/how-to-deploy-cloud-functions-with-secrets-from-secret-manager-using-cloud-build)に同じ問題に遭遇した人がいる。)

参考資料
[シークレットの使用](https://cloud.google.com/functions/docs/configuring/secrets)
[gcloud beta run deploy#--set-secrets](https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy#--set-secrets)