Closed14

公式チェックリストに従って Cloud Functions の安全性を高める

9sako69sako6

Firebase セキュリティチェックリストというものがあり、Cloud Functions については下記3項目が推奨されている。曰く、

  • Cloud Functions の関数の環境変数には機密情報を含めない
  • 機密情報を暗号化する
  • シンプルな関数の方が安全です。複雑にする必要がある場合は、Cloud Run を検討してください。
    • どのくらいの複雑度を指しているかわからない。Cloud Functions for Firebase を使いたいのと、実質 Cloud Functions は Cloud Run だろうということでこの項目は今回対応しない

最初の2項目を対応していく。

https://firebase.google.com/support/guides/security-checklist?hl=ja#cloud_function_safety

9sako69sako6

Cloud Secret Manager から機密情報を読み取る

Cloud Functions の関数の環境変数には機密情報を含めない
機密情報を暗号化する

Cloud Functions は Cloud Secret Manager から機密情報を読み取るようにしよう。

9sako69sako6

エミュレータを使っているローカルと CI では、.secret.local ファイルに secrets を .env ファイルと同じ要領で書き込む。
各関数においては、必要な secrets を読み込む設定をしておく。

index.ts
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 などとして読み込める。

9sako69sako6

自動デプロイ時にどうやって 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 が必要なため)

9sako69sako6

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
9sako69sako6

Secret はセットされているけど Cloud Functions から読み込めてなさげでエラーになる。

9sako69sako6

これ毎回 secrets のバージョンを更新しているけど変更ない時はスキップしたい

9sako69sako6

エミュレータで demo-* などのプロジェクト ID を使っている場合に、変数を読み込めなくてエラーになる。下記と同じ問題。1年以上解決されていない。本番環境で Secret Manager から読み込むことはできるが、ローカルで開発できないのは厳しい。issue にあるワークアラウンドも機能しない。

https://github.com/firebase/firebase-tools/issues/5520

9sako69sako6

先日リリースされた v13.15.1 で解決したとアナウンスがあるので再度試す。

9sako69sako6

本番環境にデプロイすると下記エラーになる。

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)
9sako69sako6

Secret の値に改行が入っており、それ故に BigQuery のクエリが壊れていた。

このスクラップは3ヶ月前にクローズされました