firebase deploy 周りの罠と対処法(その2)

クラウドのインフラ周りでは適切な権限管理は必要になります。
開発環境はともかく、公開される本番環境についてはできる限り最小権限の原則に沿って構築を行いたいものです。
というところで今回は、GCP/Firebase 周りの権限がお題です。
この2つはそれぞれ管理コンソールがありますが、実態としては統合されている部分もあり、なかなかわかりづらかったのでその辺りを整理、まとめてみました。

構成

今回の例は前提として以下のような構成で開発を行っているものとします。

  • Webアプリケーション
  • Cloud Functions を使用したバッチ処理あり
  • 開発環境と本番環境でプロジェクトを分ける
  • Firebase Authentication によるユーザー認証機能
  • データベースとしてFirestore を使用
  • Firebase hosting / GCP Cloud Run にデプロイ
  • Github Action による自動デプロイ
  • 開発は開発者のローカル環境で行い、GCPで動く開発環境もある

プリンシパル(サービスアカウントやユーザー)

最低限必要なプリンシパル(サービスアカウント、またはユーザーと考えて良いと思われます。実行主体のこと)は以下になります。

  • 開発環境用
    • 開発用サービスアカウント: Firebase のデフォルトサービスアカウントがあるのでこれを使用する。
      • firebase-adminsdk-xxxxxx@xxxxxxxxx.iam.gserviceaccount.com のような名称
      • firebase のコンソールからJSON形式の認証ファイルをダウンロードできる
    • GCP上の開発環境のアプリケーション/Functionsを実行するサービスアカウント(run/functionの詳細で確認できる): 自動で作成される。
    • ややこしいが上記の firebase-adminsdk.. のサービスアカウントとは別に {projectId}-compute@developer.gserviceaccount.com というサービスアカウントが使用される
    • 開発者のユーザー、ローカルからデプロイしたり、gcloud コマンドで何か操作する時に必要
  • 本番環境用
    • Github Actionでデプロイを行うサービスアカウント: デプロイ用のロールのみで良い(はず)
    • サービスアカウントキーを発行してGithub Action のシークレットに登録する
    • アプリケーション/Functions実行のサービスアカウント: 必要なロールのみ与える
      • Firestore: Cloud Datastore ユーザー
      • Firebase Authentication:
      • その他必要に応じて
    • ちなみにfirebase deploy コマンドではアプリケーション実行のサービスアカウントはデフォルトのもので決め打ちになり変更できません。(今回の罠)
      • 細かく管理したい場合は、前回の記事と同じように firebase deploy ではなく gcloud functions deploy を使用することで任意のサービスアカウントを指定できる。

ロールと権限

サービスアカウントに権限を持たせる場合、まとまった権限を持ったロールを割り当てるやり方と直接権限を割り当てるやり方がありますが、これは原則前者のロール割り当てで行うのが簡単です。
また、ロールにはオーナー、編集者、閲覧者のような過剰な権限を持つロールもありますが原則これらわ使わないほうが良いでしょう。

Firebase SDK の認証について

Firebase のSDKにはサーバー側で使用する firebaseAdmin とクライアント(ブラウザ)で使用するfiresbase があります。それらの認証についてのまとめです。

  • firebaseAdmin については実はGCP上で実行する限り基本 credential/cert を渡す必要はありません。
    • アプリケーション実行のサービスアカウントがFirestore用のロールなど必要なロールを持っていれば勝手にやってくれます。
      • 本番環境でシークレットキーを使用する必要が無くなるのでこのやり方を推奨。
    • ローカル実行の場合も自身のユーザーが適切な権限を持っていてgcloud login/ firebase login していれば良いはずです。
      • なのですが、試したところFirebase Authenticationの操作だけエラーになってしまいうまくいkませんでした。(原因不明)
      • なのでadmin sdk の秘密鍵を使うのが丸いです。
  • 一方、ブラウザ側のfirebase clientは常に認証が必要です。(コンソールで取得できるapiKey等のコピペでOK)

おまけ

サービスアカウントを指定してデプロイするコマンド

gcloud functions deploy my-server \
  --runtime nodejs20 \
  --trigger-http \
  --entry-point GenerateExcel \
  --gen2 \
  --region asia-northeast1 \
  --service-account=name@{projectid}.iam.gserviceaccount.com \
  --timeout=540

アプリケーションを実行するサービスアカウントに割り当てるロールでよく使われると思われるもの

  • Cloud Datastore ユーザー: Firestoreへのアクセスロール。名前がわかりづらいです。
  • Firebase Authentication 管理者: Firebase Authentication を使用する場合
  • Secret Manager のシークレットアクセサー: Secret Manager へのアクセス
  • Storage オブジェクト ユーザー: Cloud Storage へのアクセス
  • サーバーレス VPC アクセスユーザー: プライベートのVPCにVPCコネクター経由でアクセスする場合に必要です。