👾

Firebase の環境構築を Terraform で自動化する

2023/03/30に公開

こんにちは!アルダグラムでエンジニアをしている @sukechannnn です。

SREチームでは、本番でも利用しているECSにデプロイして動作確認できるテスト環境を、用途に応じて増やせる基盤の整備を行い、4月から運用を開始する予定です。

その中で、複数の Firebase プロジェクトを同じ設定で構築する必要があり、手動での構築に課題を感じていました。そこで Terraform で構築・管理できないか?と調べてみたところ、google-beta providergoogle_firebase_project resource があり、それを用いることで Firebase プロジェクトを簡単に構築できるようになりました!

この記事ではそのやり方について、サンプルコードと共に説明していきます。

ちなみに、ここで説明する内容は、以下の公式ブログにもまとまっています。
Get started with Terraform and Firebase

Terraform で Firebase プロジェクトを立ち上げる

Firebase のプロジェクトを追加します。

terraform {
  required_providers {
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 4.0"
    }
  }
}

provider "google-beta" {
  billing_project       = "existing_project_id"
  user_project_override = true
  region                = "asia-northeast1"
}

# Firebase プロジェクト用の GCP プロジェクトを立ち上げる
resource "google_project" "default" {
  provider = google-beta

  # project_id は全世界で一意になる必要がある
  project_id      = "project_id"
  name            = "project_name"
  org_id          = 1234567890
  billing_account = "123456-ABCDEF-1A2B3C"

  # Firebase のプロジェクトとして表示するために必要
  labels = {
    "firebase" = "enabled"
  }
}

# Firebase のプロジェクトを立ち上げる
resource "google_firebase_project" "default" {
  provider = google-beta
  project  = google_project.default.project_id

  depends_on = [
    google_project_service.default,
  ]
}

google-beta provider の billing_project は「すでに作成済みの請求アカウントが紐付けられている firebase アカウント」を設定する必要があるようです(公式ドキュメントの説明が分かりづらいのですが、試したら動いたので合ってそう)。
billing_project を指定した場合は、併せて user_project_override = true を設定する必要があります。

google_project resource で Firebase 用の GCP プロジェクトを立ち上げます。この時 billing_account を渡してあげると、最初から Blaze プランなプロジェクトを立ち上げることができます。べんり!

そして google_firebase_project で Firebase プロジェクトを立ち上げます。depends_on に注意しながら設定してください。

作成したプロジェクトに設定を追加

上記で作成したプロジェクトに設定を追加していきます。

各種APIを有効化する

例えば Cloud Functions をデプロイするためには CloudBuild API の有効化が必要だったり、Firestore のルールを設定するためには Firestore API が必要だったりします。それらをまとめて有効化するには以下を追加します。
このコードでは、CloudBuild, Firestore に加えて、この後説明する Firebase Authentication を使うための API も有効化しています。

# Firebase プロジェクトが作られてから60秒待つ
resource "time_sleep" "wait_60_seconds" {
  depends_on = [google_project.default]

  create_duration = "60s"
}

# 各種APIを有効化する
resource "google_project_service" "default" {
  provider = google-beta
  project  = google_project.default.project_id
  for_each = toset([
    "cloudbuild.googleapis.com",
    "firestore.googleapis.com",
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "identitytoolkit.googleapis.com",
  ])
  service = each.key

  disable_on_destroy = false
  depends_on         = [time_sleep.wait_60_seconds]
}

こういう作業は忘れると地味にハマるポイントなので、コード化できていると嬉しいですね。

ちなみに、Cloud Functions をデプロイするためには追加で権限の設定が必要だったりするので、お気をつけください。

参考: Cloud Functions for Firebase の権限

Firebase Authentication で メール/パスワード認証 を有効にする

以下のコードで Firebase Authentication、メール/パスワード認証 を有効にできます。

# Firebase Authentication を有効化する
resource "google_identity_platform_config" "default" {
  provider = google-beta
  project  = google_project.default.project_id

  depends_on = [
    google_project_service.default,
  ]
}

# メール/パスワード認証 を有効にする
resource "google_identity_platform_project_default_config" "default" {
  provider = google-beta
  project  = google_project.default.project_id
  sign_in {
    allow_duplicate_emails = false

    email {
      enabled           = true
      password_required = true
    }
  }

  # email/password の認証を有効化する前に Firebase Authentication が有効化されるのを待つ
  depends_on = [
    google_identity_platform_config.default
  ]
}

ちなみに、Google認証 などの ID provider を追加するためには google_identity_platform_default_supported_idp_config を利用するのですが、これを使うためには client_id, client_secret が必要なので、設定が少し面倒でした。Google認証 などは Firebase コンソールからポチッとする方が楽かもしれません…。

Firestore を有効化する

以下のコードで Firestore を有効にできます。

resource "google_app_engine_application" "firebase" {
  provider      = google-beta
  project       = google_project.default.project_id
  location_id   = "asia-northeast1"
  database_type = "CLOUD_FIRESTORE"
}

Webアプリを追加する

以下のコードでWebアプリを追加できます。

resource "google_firebase_web_app" "default" {
  provider        = google-beta
  project         = google_project.default.project_id
  display_name    = "web_app"
  deletion_policy = "DELETE"

  depends_on = [google_firebase_project.default]
}

また、google_firebase_web_app_config の data source を利用することで、firebase SDK を有効化するために使う id や key を output で出力できます。地味にべんりです!

data "google_firebase_web_app_config" "default" {
  provider   = google-beta
  web_app_id = google_firebase_web_app.default.app_id
  project    = google_firebase_project.default.project
}

output "firebase_project_id" {
  value = google_project.default.project_id
}

output "firebase_web_app_api_key" {
  value = data.google_firebase_web_app_config.default.api_key
}

output "firebase_web_app_auth_domain" {
  value = data.google_firebase_web_app_config.default.auth_domain
}

output "firebase_web_app_id" {
  value = data.google_firebase_web_app_config.default.web_app_id
}

output "firebase_web_app_messaging_sender_id" {
  value = data.google_firebase_web_app_config.default.messaging_sender_id
}

output "firebase_web_app_storage_bucket" {
  value = data.google_firebase_web_app_config.default.storage_bucket
}

Android / iOS を追加する

Android, iOS のアプリも追加できます。

Android
resource "google_firebase_android_app" "default" {
  provider     = google-beta
  project      = google_project.default.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  depends_on = [google_firebase_project.default]
}
iOS
resource "google_firebase_apple_app" "default" {
  provider     = google-beta
  project      = google_project.default.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  depends_on = [google_firebase_project.default]
}

まとめ

Terraform で Firebase を立ち上げてみました。

私たちは上記コードを以下のような構成で module 化して、環境を簡単に追加できるようにしています。

$ tree .
.
├── README.md
└── gcp
     ├── environments
     │   ├── qa1
     │   │   └── main.tf
     │   ├── qa2
     │   │   └── main.tf
     │   └── qa3
     │       └── main.tf
     └── modules
         └── firebase
             ├── main.tf
             ├── outputs.tf
             └── variables.tf

最初から Terraform 化するメリットはあまりないかもしれませんが、私たちのように多くの Firebase プロジェクトを管理したい場合には非常に便利でした。

参考になれば幸いです!

アルダグラム Tech Blog

Discussion