公式チェックリストに従って Cloud Functions の安全性を高める
Firebase セキュリティチェックリストというものがあり、Cloud Functions については下記3項目が推奨されている。曰く、
- Cloud Functions の関数の環境変数には機密情報を含めない
- 機密情報を暗号化する
- シンプルな関数の方が安全です。複雑にする必要がある場合は、Cloud Run を検討してください。
- どのくらいの複雑度を指しているかわからない。Cloud Functions for Firebase を使いたいのと、実質 Cloud Functions は Cloud Run だろうということでこの項目は今回対応しない
最初の2項目を対応していく。
Cloud Secret Manager から機密情報を読み取る
Cloud Functions の関数の環境変数には機密情報を含めない
機密情報を暗号化する
Cloud Functions は Cloud Secret Manager から機密情報を読み取るようにしよう。
エミュレータを使っているローカルと CI では、.secret.local ファイルに secrets を .env ファイルと同じ要領で書き込む。
各関数においては、必要な secrets を読み込む設定をしておく。
export const addWorkIndex = onDocumentWritten(
{
memory: '1GiB',
document: 'works/{workId}',
secrets: ['BIGQUERY_PROJECT_ID', 'BIGQUERY_DATASET_ID'],
},
addWorkIndexHandler,
);
setGlobalOptions
で全ての secrets を読み込むこともできるが、関数がコールドスタートから起き上がるたびに Secret Manager から読み込まれるので無駄に読み取り回数が増えそう。個別に設定した。
設定した関数内では process.env.BIGQUERY_PROJECT_ID
などとして読み込める。
自動デプロイ時にどうやって Secret Manager に機密情報を登録するか。
firebase functions:secrets:set KEY_NAME=KEY_VALUE
でいけそう。
追記:
CI/CD パイプラインから追加すると、毎回バージョンが更新される上、変数が多いとかなり時間がかかる。
firebase functions:secrets:set
は CI/CD パイプラインで使う想定のものではないと思われるので、手動でsecret を登録するのがいいだろう。
デプロイに使用しているサービスアカウント等は roles/secretmanager.admin
権限を持っている必要がある。(secretmanager.secrets.setIamPolicy
が必要なため)
CI/CD から Secret Manager に登録するコマンドはこのようになった。
credentials.json は Workload Identity で生成したもの。roles/secretmanager.admin
権限が必要だった。
echo $MY_PUBLIC_S3_URL | GOOGLE_APPLICATION_CREDENTIALS=credentials.json firebase functions:secrets:set --project $MY_PROJECT_ID --data-file=- PUBLIC_S3_URL
追記:
これで登録すると値に改行が入ってアプリが壊れた。下記を実行して手で値を入れた方がいい。
firebase functions:secrets:set --project $MY_PROJECT_ID KEY_NAME
Secret はセットされているけど Cloud Functions から読み込めてなさげでエラーになる。
defineSecret()
を使う必要があった。
CI/CD パイプラインからデプロイしたらエラー
Secret environment variable overlaps non secret environment variable: XXX
.env
ファイルと干渉している説がある。
これ毎回 secrets のバージョンを更新しているけど変更ない時はスキップしたい
エミュレータで demo-*
などのプロジェクト ID を使っている場合に、変数を読み込めなくてエラーになる。下記と同じ問題。1年以上解決されていない。本番環境で Secret Manager から読み込むことはできるが、ローカルで開発できないのは厳しい。issue にあるワークアラウンドも機能しない。
先日リリースされた v13.15.1 で解決したとアナウンスがあるので再度試す。
環境
- firebase-tools v13.15.4
- firebase-functions@5.1.1
上記エラーが起きなくなった。
本番環境にデプロイすると下記エラーになる。
Error: Syntax error: Unclosed identifier literal at [20:12]
at new ApiError (/workspace/node_modules/@google-cloud/common/build/src/util.js:75:15)
at Util.parseHttpRespBody (/workspace/node_modules/@google-cloud/common/build/src/util.js:210:38)
at Util.handleResp (/workspace/node_modules/@google-cloud/common/build/src/util.js:151:117)
at /workspace/node_modules/@google-cloud/common/build/src/util.js:534:22
at onResponse (/workspace/node_modules/retry-request/index.js:259:7)
at /workspace/node_modules/teeny-request/build/src/index.js:226:13
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Secret の値に改行が入っており、それ故に BigQuery のクエリが壊れていた。