開始使用 Terraform 和 Firebase

Firebase 開始支援 Terraform。如果您的團隊希望自動化及標準化 Firebase 專案建立作業,並提供特定資源和啟用服務,建議您使用 Firebase 搭配 Terraform 使用。

搭配 Firebase 使用 Terraform 的基本工作流程包括:

  • 建立並自訂 Terraform 設定檔 (.tf 檔案),指定要佈建的基礎架構 (也就是要佈建的資源和要啟用的服務)。

  • 使用與 Terraform 介面的 gcloud CLI 指令,佈建 .tf 檔案中指定的基礎架構。

Terraform 和 Firebase 有哪些用途?

本指南中的一般工作流程範例是使用 Android 應用程式建立新的 Firebase 專案。不過,您可以透過 Terraform 執行更多操作,例如:

  • 使用 Terraform 刪除及修改現有基礎架構。

  • 使用 Terraform 管理特定產品的設定和工作,例如:

    • 啟用 Firebase Authentication 登入資訊提供者。
    • 建立 Cloud Storage 儲存桶或資料庫執行個體,並為其部署 Firebase Security Rules

您可以使用標準的 Terraform 設定檔和指令完成所有這些工作。為協助您完成這項工作,我們提供幾個常見用途的 Terraform 設定檔範例



搭配 Firebase 使用 Terraform 的一般工作流程

必要條件

本指南介紹如何在 Firebase 中使用 Terraform,因此假設您具備基本的 Terraform 操作能力。請先完成下列必要條件,再開始這個工作流程。

  • 安裝 Terraform,並透過官方教學課程熟悉 Terraform。

  • 安裝 Google Cloud CLI (gcloud CLI)。使用使用者帳戶服務帳戶登入。

    • 如果使用的是使用者帳戶,您必須接受 Firebase 服務條款 (Firebase ToS)。如果您可以在 Firebase 控制台中查看 Firebase 專案,表示您已接受 Firebase 服務條款。
    • 如要讓 Terraform 執行特定動作 (例如建立專案),必須符合下列條件:
      • 使用者或服務帳戶必須具備適用的 IAM 存取權,才能執行這些動作。
      • 如果使用者或服務帳戶隸屬於 Google Cloud 機構,則機構政策必須允許帳戶執行這些動作。


步驟 1:建立並自訂 Terraform 設定檔

Terraform 設定檔需要兩個主要部分 (詳情請見下文):

設定 provider

無論涉及哪些 Firebase 產品或服務,都必須設定 provider

  1. 在本機目錄中建立 Terraform 設定檔 (例如 main.tf 檔案)。

    在本指南中,您將使用這個設定檔來指定 provider 設定,以及您希望 Terraform 建立的所有基礎架構。不過,您可以選擇如何納入供應器設定。

    您可以透過下列選項,將 provider 設定納入其他 Terraform 設定:

    • 選項 1:在單一 Terraform .tf 設定檔頂端加入此值 (如本指南所示)。

      • 如果您剛開始使用 Terraform,或只是想透過 Firebase 試用 Terraform,請使用這個選項。
    • 選項 2:除了您指定要建立基礎架構的 .tf 檔案 (例如 main.tf 檔案) 外,請在獨立的 .tf 檔案 (例如 provider.tf 檔案) 中加入該值。

      • 如果您是需要將設定標準化的大型團隊成員,請使用這個選項。
      • 執行 Terraform 指令時,provider.tf 檔案和 main.tf 檔案必須位於相同目錄中。

  2. main.tf 檔案頂端加入下列 provider 設定。

    您必須使用 google-beta 供應工具,因為這是使用 Firebase 與 Terraform 的 Beta 版。在實際工作環境中使用時請謹慎小心。

    # Terraform configuration to set up providers by version.
    terraform {
      required_providers {
        google-beta = {
          source  = "hashicorp/google-beta"
          version = "~> 5.0"
        }
      }
    }
    
    # Configures the provider to use the resource block's specified project for quota checks.
    provider "google-beta" {
      user_project_override = true
    }
    
    # Configures the provider to not use the resource block's specified project for quota checks.
    # This provider should only be used during project creation and initializing services.
    provider "google-beta" {
      alias = "no_user_project_override"
      user_project_override = false
    }

    進一步瞭解在 Firebase 中使用 Terraform 時的不同類型的專案相關屬性 (包括本指南所稱的「配額檢查專案」)。

  3. 請繼續閱讀下一節,完成設定檔並指定要建立的基礎架構。

使用 resource 區塊指定要建立的基礎架構

在 Terraform 設定檔 (本指南的 main.tf 檔案) 中,您需要指定要讓 Terraform 建立的所有基礎架構 (也就是您要佈建的所有資源,以及要啟用的所有服務)。您可以在本指南中查看支援 Terraform 的所有 Firebase 資源完整清單。

  1. 開啟 main.tf 檔案。

  2. provider 設定下方,加入下列 resource 區塊的設定。

    這個基本範例會建立新的 Firebase 專案,然後在該專案中建立 Firebase Android 應用程式。

    # Terraform configuration to set up providers by version.
    ...
    
    # Configures the provider to use the resource block's specified project for quota checks.
    ...
    
    # Configures the provider to not use the resource block's specified project for quota checks.
    ...
    
    # Creates a new Google Cloud project.
    resource "google_project" "default" {
      provider   = google-beta.no_user_project_override
    
      name       = "Project Display Name"
      project_id = "project-id-for-new-project"
      # Required for any service that requires the Blaze pricing plan
      # (like Firebase Authentication with GCIP)
      billing_account = "000000-000000-000000"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    # Enables required APIs.
    resource "google_project_service" "default" {
      provider = google-beta.no_user_project_override
      project  = google_project.default.project_id
      for_each = toset([
        "cloudbilling.googleapis.com",
        "cloudresourcemanager.googleapis.com",
        "firebase.googleapis.com",
        # Enabling the ServiceUsage API allows the new project to be quota checked from now on.
        "serviceusage.googleapis.com",
      ])
      service = each.key
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enables Firebase services for the new project created above.
    resource "google_firebase_project" "default" {
      provider = google-beta
      project  = google_project.default.project_id
    
      # Waits for the required APIs to be enabled.
      depends_on = [
        google_project_service.default
      ]
    }
    
    # Creates a Firebase Android App in the new project created above.
    resource "google_firebase_android_app" "default" {
      provider = google-beta
    
      project      = google_project.default.project_id
      display_name = "My Awesome Android app"
      package_name = "awesome.package.name"
    
      # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
      depends_on = [
        google_firebase_project.default,
      ]
    }

如果您不熟悉專案和應用程式資源的基礎架構,請參閱下列說明文件:

# Terraform configuration to set up providers by version.
...

# Configures the provider to use the resource block's specified project for quota checks.
...

# Configures the provider to not use the resource block's specified project for quota checks.
...

# Creates a new Google Cloud project.
resource "google_project" "default" {
  # Use the provider that enables the setup of quota checks for a new project
  provider   = google-beta.no_user_project_override

  name            = "Project Display Name"        // learn more about the project name
  project_id      = "project-id-for-new-project"  // learn more about the project ID
  # Required for any service that requires the Blaze pricing plan
  # (like Firebase Authentication with GCIP)
  billing_account = "000000-000000-000000"

  # Required for the project to display in any list of Firebase projects.
  labels = {
    "firebase" = "enabled"  // learn more about the Firebase-enabled label
  }
}

# Enables required APIs.
resource "google_project_service" "default" {
  # Use the provider without quota checks for enabling APIS
  provider = google-beta.no_user_project_override
  project  = google_project.default.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebase.googleapis.com",
    # Enabling the ServiceUsage API allows the new project to be quota checked from now on.
    "serviceusage.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
# This action essentially "creates a Firebase project" and allows the project to use
# Firebase services (like Firebase Authentication) and
# Firebase tooling (like the Firebase console).
# Learn more about the relationship between Firebase projects and Google Cloud.
resource "google_firebase_project" "default" {
  # Use the provider that performs quota checks from now on
  provider = google-beta

  project  = google_project.default.project_id

  # Waits for the required APIs to be enabled.
  depends_on = [
    google_project_service.default
  ]
}

# Creates a Firebase Android App in the new project created above.
# Learn more about the relationship between Firebase Apps and Firebase projects.
resource "google_firebase_android_app" "default" {
  provider = google-beta

  project      = google_project.default.project_id
  display_name = "My Awesome Android app"  # learn more about an app's display name
  package_name = "awesome.package.name"    # learn more about an app's package name

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.default,
  ]
}


步驟 2:執行 Terraform 指令,建立指定的基礎架構

如要佈建資源並啟用 main.tf 檔案中指定的服務,請在 main.tf 檔案所在的目錄中執行下列指令。如要進一步瞭解這些指令,請參閱 Terraform 說明文件

  1. 如果這是您第一次在目錄中執行 Terraform 指令,則需要初始化設定目錄並安裝 Google Terraform 供應器。執行下列指令即可:

    terraform init
  2. 執行下列指令,建立 main.tf 檔案中指定的基礎架構:

    terraform apply
  3. 確認所有項目是否已如預期佈建或啟用:

    • 選項 1:執行下列指令,查看終端機顯示的設定:

      terraform show
    • 選項 2:Firebase 控制台中查看 Firebase 專案。



支援 Terraform 的 Firebase 資源

下列 Firebase 和 Google 資源支援 Terraform。我們會持續新增更多資源!因此,如果您找不到要使用 Terraform 管理的資源,請盡快再次查看是否可用,或在 GitHub 存放區中提出問題


Firebase 專案和應用程式管理

  • google_firebase_project:在現有的 Google Cloud 專案中啟用 Firebase 服務

  • Firebase 應用程式


Firebase Authentication

尚未支援:

  • 透過 Terraform 設定多重驗證 (MFA)

Firebase Data Connect


Firebase Realtime Database

尚未支援:


Cloud Firestore

  • google_firestore_database - 建立 Cloud Firestore 例項

  • google_firestore_index:啟用 Cloud Firestore 的效率查詢

  • google_firestore_document:使用集合中的特定文件為 Cloud Firestore 例項播種

    重要事項:請勿在這個種子文件中使用實際的使用者或正式版資料。


Cloud Storage for Firebase

  • google_firebase_storage_bucket:讓現有的 Cloud Storage 儲存體可供 Firebase SDK、驗證和 Firebase Security Rules 存取

  • google_storage_bucket_object:將物件新增至 Cloud Storage 值區

    重要事項:請勿在這個檔案中使用實際的使用者或實際生產資料。


Firebase Security Rules (適用於 Cloud FirestoreCloud Storage)

請注意,Firebase Realtime Database 會為其 Firebase Security Rules 使用不同的佈建系統。

  • google_firebaserules_ruleset:定義套用至 Cloud Firestore 例項或 Cloud Storage 值區的 Firebase Security Rules

  • google_firebaserules_release:將特定規則集部署至 Cloud Firestore 執行個體或 Cloud Storage 值區


Firebase App Check


Firebase Extensions



常見用途的 Terraform 設定檔範例

這個設定會建立新的 Google Cloud 專案,並將專案與 Cloud Billing 帳戶建立關聯 (Firebase Authentication 需要使用 GCIP 的 Blaze 定價方案),為專案啟用 Firebase 服務,使用 GCIP 設定 Firebase Authentication,並將三種不同的應用程式類型註冊至專案。

請注意,您必須啟用 GCIP,才能透過 Terraform 設定 Firebase Authentication

# Creates a new Google Cloud project.
resource "google_project" "auth" {
  provider  = google-beta.no_user_project_override
  folder_id = "folder-id-for-new-project"
  name            = "Project Display Name"
  project_id      = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required for Firebase Authentication with GCIP).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "auth" {
  provider = google-beta.no_user_project_override
  project  = google_project.auth.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "identitytoolkit.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "auth" {
  provider = google-beta
  project  = google_project.auth.project_id

  depends_on = [
    google_project_service.auth,
  ]
}

# Creates an Identity Platform config.
# Also enables Firebase Authentication with Identity Platform in the project if not.
resource "google_identity_platform_config" "auth" {
  provider = google-beta
  project  = google_project.auth.project_id

  # Auto-deletes anonymous users
  autodelete_anonymous_users = true

  # Configures local sign-in methods, like anonymous, email/password, and phone authentication.
  sign_in {
    allow_duplicate_emails = true

    anonymous {
      enabled = true
    }

    email {
      enabled = true
      password_required = false
    }

    phone_number {
      enabled = true
      test_phone_numbers = {
        "+11231231234" = "000000"
      }
    }
  }

  # Sets an SMS region policy.
  sms_region_config {
    allowlist_only {
      allowed_regions = [
        "US",
        "CA",
      ]
    }
  }

  # Configures blocking functions.
  blocking_functions {
    triggers {
      event_type = "beforeSignIn"
      function_uri = "https://us-east1-${google_project.auth.project_id}.cloudfunctions.net/before-sign-in"
    }
    forward_inbound_credentials {
      refresh_token = true
      access_token = true
      id_token = true
    }
  }

  # Configures a temporary quota for new signups for anonymous, email/password, and phone number.
  quota {
    sign_up_quota_config {
      quota = 1000
      start_time = ""
      quota_duration = "7200s"
    }
  }

  # Configures authorized domains.
  authorized_domains = [
    "localhost",
    "${google_project.auth.project_id}.firebaseapp.com",
    "${google_project.auth.project_id}.web.app",
  ]

  # Wait for identitytoolkit.googleapis.com to be enabled before initializing Authentication.
  depends_on = [
    google_project_service.auth,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

這個設定會建立新的 Google Cloud 專案、為專案啟用 Firebase 服務,並佈建 Data Connect 服務。

# Creates a new Google Cloud project.
resource "google_project" "dataconnect" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required to use Firebase Data Connect).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "services" {
  provider = google-beta.no_user_project_override
  project  = google_project.dataconnect.project_id
  for_each = toset([
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedataconnect.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created earlier.
resource "google_firebase_project" "dataconnect" {
  provider = google-beta
  project  = google_project.dataconnect.project_id

  depends_on = [google_project_service.services]
}

# Create a Firebase Data Connect service
resource "google_firebase_data_connect_service" "dataconnect-default" {
  project         = google_firebase_project.dataconnect.project
  location        = "name-of-region-for-service"
  service_id      = "${google_firebase_project.dataconnect.project}-default-fdc"
  deletion_policy = "DEFAULT"
}

這個設定會建立新的 Google Cloud 專案、為專案啟用 Firebase 服務、佈建專案的預設 Realtime Database 例項,並將三種不同的應用程式類型註冊至專案。

# Creates a new Google Cloud project.
resource "google_project" "rtdb" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "rtdb" {
  provider = google-beta.no_user_project_override
  project  = google_project.rtdb.project_id
  for_each = toset([
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedatabase.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "rtdb" {
  provider = google-beta
  project  = google_project.rtdb.project_id
}

# Provisions the default Realtime Database default instance.
resource "google_firebase_database_instance" "database" {
  provider    = google-beta
  project     = google_project.rtdb.project_id
  # See available locations: https://firebase.google.com/docs/database/locations
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "${google_project.rtdb.project_id}-default-rtdb"
  type        = "DEFAULT_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

這個設定會建立新的 Google Cloud 專案,並將專案與 Cloud Billing 帳戶建立關聯 (多個 Realtime Database 執行個體需要使用 Blaze 定價方案),為專案啟用 Firebase 服務、佈建多個 Realtime Database 執行個體 (包括專案的預設 Realtime Database 執行個體),以及在專案中註冊三種不同的應用程式類型。

# Creates a new Google Cloud project.
resource "google_project" "rtdb-multi" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associate the project with a Cloud Billing account
  # (required for multiple Realtime Database instances).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "rtdb-multi" {
  provider = google-beta.no_user_project_override
  project  = google_project.rtdb-multi.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedatabase.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "rtdb-multi" {
  provider = google-beta
  project  = google_project.rtdb-multi.project_id
}

# Provisions the default Realtime Database default instance.
resource "google_firebase_database_instance" "database-default" {
  provider    = google-beta
  project     = google_project.rtdb-multi.project_id
  # See available locations: https://firebase.google.com/docs/database/locations
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "${google_project.rtdb-multi.project_id}-default-rtdb"
  type        = "DEFAULT_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Provisions an additional Realtime Database instance.
resource "google_firebase_database_instance" "database-additional" {
  provider    = google-beta
  project     = google_project.rtdb-multi.project_id
  # See available locations: https://firebase.google.com/docs/projects/locations#rtdb-locations
  # This location doesn't need to be the same as the default database instance.
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "name-of-additional-database-instance"
  type        = "USER_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

這個設定會建立新的 Google Cloud 專案、為專案啟用 Firebase 服務、佈建專案的預設 Cloud Firestore 例項,並將三種不同的應用程式類型註冊至專案。

它也會為預設 Cloud Firestore 例項提供 Firebase Security Rules、建立 Cloud Firestore 索引,以及新增含有種子資料的 Cloud Firestore 文件。

# Creates a new Google Cloud project.
resource "google_project" "firestore" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "firestore" {
  provider = google-beta.no_user_project_override
  project  = google_project.firestore.project_id
  for_each = toset([
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "firestore.googleapis.com",
    "firebaserules.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "firestore" {
  provider = google-beta
  project  = google_project.firestore.project_id
}

# Provisions the Firestore database instance.
resource "google_firestore_database" "firestore" {
  provider                    = google-beta
  project                     = google_project.firestore.project_id
  name                        = "(default)"
  # See available locations: https://firebase.google.com/docs/firestore/locations
  location_id                 = "name-of-region"
  # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs, authentication, and Firebase Security Rules.
  type                        = "FIRESTORE_NATIVE"
  concurrency_mode            = "OPTIMISTIC"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Firestore.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a ruleset of Firestore Security Rules from a local file.
resource "google_firebaserules_ruleset" "firestore" {
  provider = google-beta
  project  = google_project.firestore.project_id
  source {
    files {
      name = "firestore.rules"
      # Write security rules in a local file named "firestore.rules".
      # Learn more: https://firebase.google.com/docs/firestore/security/get-started
      content = file("firestore.rules")
    }
  }

  # Wait for Firestore to be provisioned before creating this ruleset.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Releases the ruleset for the Firestore instance.
resource "google_firebaserules_release" "firestore" {
  provider     = google-beta
  name         = "cloud.firestore"  # must be cloud.firestore
  ruleset_name = google_firebaserules_ruleset.firestore.name
  project      = google_project.firestore.project_id

  # Wait for Firestore to be provisioned before releasing the ruleset.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Adds a new Firestore index.
resource "google_firestore_index" "indexes" {
  provider = google-beta
  project  = google_project.firestore.project_id

  collection  = "quiz"
  query_scope = "COLLECTION"

  fields {
    field_path = "question"
    order      = "ASCENDING"
  }

  fields {
    field_path = "answer"
    order      = "ASCENDING"
  }

  # Wait for Firestore to be provisioned before adding this index.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Adds a new Firestore document with seed data.
# Don't use real end-user or production data in this seed document.
resource "google_firestore_document" "doc" {
  provider    = google-beta
  project     = google_project.firestore.project_id
  collection  = "quiz"
  document_id = "question-1"
  fields      = "{\"question\":{\"stringValue\":\"Favorite Database\"},\"answer\":{\"stringValue\":\"Firestore\"}}"

  # Wait for Firestore to be provisioned before adding this document.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

這是 Cloud Firestore Security Rules 的規則集,應位於名為 firestore.rules 的本機檔案中。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow read, create, update: if request.auth != null;
    }
  }
}

這個設定會建立新的 Google Cloud 專案,並將專案與 Cloud Billing 帳戶建立關聯 (需要 Blaze 定價方案才能使用其他桶),為專案啟用 Firebase 服務、佈建其他非預設 Cloud Storage 桶,並在專案中註冊三種不同的應用程式類型。

它也會為每個 Cloud Storage bucket 佈建 Firebase Security Rules,並將檔案上傳至其中一個 Cloud Storage bucket。

# Creates a new Google Cloud project.
resource "google_project" "storage-multi" {
  provider  = google-beta.no_user_project_override
  folder_id = "folder-id-for-new-project"
  name            = "Project Display Name"
  project_id      = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required for multiple Cloud Storage buckets).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "storage-multi" {
  provider = google-beta.no_user_project_override
  project  = google_project.storage-multi.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebaserules.googleapis.com",
    "firebasestorage.googleapis.com",
    "storage.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "storage-multi" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
}

# Provisions a Cloud Storage bucket.
resource "google_storage_bucket" "bucket-1" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  name     = "name-of-storage-bucket"
  # See available locations: https://cloud.google.com/storage/docs/locations#available-locations
  location = "name-of-region-for-bucket"
}

# Provisions an additional Cloud Storage bucket.
resource "google_storage_bucket" "bucket-2" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  name     = "name-of-additional-storage-bucket"
  # See available locations: https://cloud.google.com/storage/docs/locations#available-locations
  # This location does not need to be the same as the existing Storage bucket.
  location = "name-of-region-for-additional-bucket"
}

# Makes the first Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
resource "google_firebase_storage_bucket" "bucket-1" {
  provider  = google-beta
  project   = google_project.storage-multi.project_id
  bucket_id = google_storage_bucket.bucket-1.name
}

# Makes the additional Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
resource "google_firebase_storage_bucket" "bucket-2" {
  provider  = google-beta
  project   = google_project.storage-multi.project_id
  bucket_id = google_storage_bucket.bucket-2.name
}

# Creates a ruleset of Firebase Security Rules from a local file.
resource "google_firebaserules_ruleset" "storage-multi" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  source {
    files {
      # Write security rules in a local file named "storage.rules"
      # Learn more: https://firebase.google.com/docs/storage/security/get-started
      name    = "storage.rules"
      content = file("storage.rules")
    }
  }

  # Wait for the Storage buckets to be provisioned before creating this ruleset.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Releases the ruleset to the first Storage bucket.
resource "google_firebaserules_release" "bucket-1" {
  provider     = google-beta
  name         = "firebase.storage/${google_storage_bucket.bucket-1.name}"
  ruleset_name = "projects/${google_project.storage-multi.project_id}/rulesets/${google_firebaserules_ruleset.storage-multi.name}"
  project      = google_project.storage-multi.project_id
}

# Releases the ruleset to the additional Storage bucket.
resource "google_firebaserules_release" "bucket-2" {
  provider     = google-beta
  name         = "firebase.storage/${google_storage_bucket.bucket-2.name}"
  ruleset_name = "projects/${google_project.storage-multi.project_id}/rulesets/${google_firebaserules_ruleset.storage-multi.name}"
  project      = google_project.storage-multi.project_id
}

# Uploads a new file to the first Storage bucket.
# Do not use real end-user or production data in this file.
resource "google_storage_bucket_object" "cat-picture-multi" {
  provider = google-beta
  name     = "cat.png"
  source   = "path/to/cat.png"
  bucket   = google_storage_bucket.bucket-1.name
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Web app"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

這是 Cloud Storage Security Rules 的規則集,應位於名為 storage.rules 的本機檔案中。

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /some_folder/{fileName} {
      allow read, write: if request.auth != null;
    }
  }
}

這個設定會建立新的 Google Cloud 專案,為專案啟用 Firebase 服務,並設定並啟用 Firebase App CheckCloud Firestore 強制執行機制,讓使用者只能透過 Android 應用程式存取。

# Creates a new Google Cloud project.
resource "google_project" "appcheck" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "services" {
  provider = google-beta.no_user_project_override
  project  = google_project.appcheck.project_id
  for_each = toset([
    "cloudresourcemanager.googleapis.com",
    "firebase.googleapis.com",
    "firebaseappcheck.googleapis.com",
    "firestore.googleapis.com",
    "serviceusage.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created earlier.
resource "google_firebase_project" "appcheck" {
  provider = google-beta
  project  = google_project.appcheck.project_id

  depends_on = [google_project_service.services]
}

# Provisions the Firestore database instance.
resource "google_firestore_database" "database" {
  provider = google-beta
  project  = google_firebase_project.appcheck.project
  name     = "(default)"
  # See available locations: https://firebase.google.com/docs/projects/locations#default-cloud-location
  location_id = "name-of-region"
  # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs, authentication, and Firebase Security Rules.
  type             = "FIRESTORE_NATIVE"
  concurrency_mode = "OPTIMISTIC"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Firestore.
  depends_on = [
    google_firebase_project.appcheck,
  ]
}

# Creates a Firebase Android App in the new project created earlier.
resource "google_firebase_android_app" "appcheck" {
  provider     = google-beta
  project      = google_firebase_project.appcheck.project
  display_name = "Play Integrity app"
  package_name = "package.name.playintegrity"
  sha256_hashes = [
    # TODO: insert your Android app's SHA256 certificate
  ]
}

# It takes a while for App Check to recognize the new app
# If your app already exists, you don't have to wait 30 seconds.
resource "time_sleep" "wait_30s" {
  depends_on      = [google_firebase_android_app.appcheck]
  create_duration = "30s"
}

# Register the Android app with the Play Integrity provider
resource "google_firebase_app_check_play_integrity_config" "appcheck" {
  provider = google-beta
  project  = google_firebase_project.appcheck.project
  app_id   = google_firebase_android_app.appcheck.app_id

  depends_on = [time_sleep.wait_30s, google_firestore_database.database]

  lifecycle {
    precondition {
      condition     = length(google_firebase_android_app.appcheck.sha256_hashes) > 0
      error_message = "Provide a SHA-256 certificate on the Android App to use App Check"
    }
  }
}

# Enable enforcement of App Check for Firestore
resource "google_firebase_app_check_service_config" "firestore" {
  provider = google-beta

  project    = google_firebase_project.appcheck.project
  service_id = "firestore.googleapis.com"

  depends_on = [google_project_service.services]
}

這個設定會建立新的 Google Cloud 專案、為專案啟用 Firebase 服務,並在專案中安裝新的 Firebase Extension 例項。如果執行個體已存在,其參數會根據設定檔中提供的值進行更新。

# Creates a new Google Cloud project.
resource "google_project" "extensions" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required to use Firebase Extensions).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "extensions" {
  provider = google-beta.no_user_project_override
  project  = google_project.extensions.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "firebase.googleapis.com",
    "firebaseextensions.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "extensions" {
  provider = google-beta
  project  = google_project.extensions.project_id

  depends_on = [
    google_project_service.extensions,
  ]
}

# Installs an instance of the "Translate Text in Firestore" extension.
# Or updates the extension if the specified instance already exists.
resource "google_firebase_extensions_instance" "translation" {
  provider = google-beta
  project = google_project.extensions.project_id

  instance_id = "translate-text-in-firestore"
  config {
    extension_ref = "firebase/firestore-translate-text"

    params = {
      COLLECTION_PATH      = "posts/comments/translations"
      DO_BACKFILL          = true
      LANGUAGES            = "ar,en,es,de,fr"
      INPUT_FIELD_NAME     = "input"
      LANGUAGES_FIELD_NAME = "languages"
      OUTPUT_FIELD_NAME    = "translated"
    }

    system_params = {
      "firebaseextensions.v1beta.function/location"                   = "us-central1"
      "firebaseextensions.v1beta.function/memory"                     = "256"
      "firebaseextensions.v1beta.function/minInstances"               = "0"
      "firebaseextensions.v1beta.function/vpcConnectorEgressSettings" = "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED"
    }
  }
}



疑難排解與常見問題

本指南在處理「projects」時,會使用下列 Terraform 屬性。

resource 區塊中的 project

建議做法:盡可能在每個 resource 區塊中加入 project 屬性

只要加入專案屬性,Terraform 就會在指定專案內的資源區塊中建立指定基礎架構。本指南和設定檔範例都採用這種做法。

請參閱 project 的官方 Terraform 說明文件。

provider 區塊中的 user_project_override

如要配置大部分資源,您應使用 user_project_override = true,也就是根據自己的 Firebase 專案檢查配額。不過,如要設定新專案,讓專案接受配額檢查,您必須先使用 user_project_override = false

請參閱 user_project_override 的官方 Terraform 說明文件。

請確認您用來執行 gcloud CLI 指令的使用者帳戶已接受 Firebase 服務條款 (Firebase ToS)。

  • 您可以使用已登入使用者帳戶的瀏覽器,嘗試在 Firebase 控制台中查看現有的 Firebase 專案,藉此進行檢查。如果您可以查看現有的 Firebase 專案,表示使用者帳戶已接受 Firebase 服務條款。

  • 如果您無法查看任何現有的 Firebase 專案,表示使用者帳戶可能尚未接受 Firebase 服務條款。如要修正這個問題,請透過 Firebase 控制台建立新的 Firebase 專案,並在建立專案時接受 Firebase 服務條款。您可以立即透過控制台的「專案設定」刪除這個專案。

請稍候幾分鐘,然後再嘗試執行 terraform apply

這可能是因為各系統的傳播延遲。請嘗試執行 terraform import,將資源匯入 Terraform 狀態,以解決這個問題。然後再試一次。terraform apply

如要瞭解如何匯入各項資源,請參閱 Terraform 說明文件中的「Import」一節 (例如 Cloud Firestore「Import」說明文件)。

如錯誤訊息所示,Terraform 可能會嘗試同時佈建多個索引和/或建立文件,並發生並行錯誤。請嘗試再次執行 terraform apply

這個錯誤表示 Terraform 不知道要針對哪個專案檢查配額。如要排解問題,請在 resource 區塊中檢查下列項目:

  • 請確認你已為 project 屬性指定值。
  • 請確認您使用的是 user_project_override = true (沒有別名) 的供應器,在 Firebase 範例中為 google-beta

以下是專案 ID 可能已存在的可能原因:

  • 與該 ID 相關聯的專案屬於其他使用者。

    • 解決方法:請選擇其他專案 ID。
  • 與該 ID 相關聯的專案最近已遭刪除 (處於軟刪除狀態)。

    • 解決方法:如果您認為與 ID 相關聯的專案屬於您,請使用 projects.get REST API 檢查專案狀態。
  • 與該 ID 相關聯的專案確實存在於目前使用者下。發生這項錯誤的可能原因可能是先前的 terraform apply 遭到中斷。

    • 解決方法:請執行下列指令:
      terraform import google_project.default PROJECT_ID 然後
      terraform import google_firebase_project.default PROJECT_ID

如果您在嘗試佈建預設 Cloud Firestore 執行個體之前,已透過 google_app_engine_application 佈建預設 Cloud Storage 儲存體,您會發現預設 Cloud Firestore 執行個體已佈建完成。請注意,已佈建的資料庫執行個體處於 Datastore 模式,這表示 Firebase SDK、驗證或 Firebase Security Rules 無法存取該執行個體。如果您想搭配這些 Firebase 服務使用 Cloud Firestore,就必須清空資料庫,然後在 Google Cloud 控制台中變更資料庫類型。

當您透過 google_app_engine_application 佈建專案的預設 Cloud Storage 值區,且專案尚未有預設 Cloud Firestore 執行個體時,google_app_engine_application 會自動佈建專案的預設 Cloud Firestore 執行個體。

因此,由於專案的預設 Cloud Firestore 例項「已」佈建,如果您嘗試再次明確佈建該預設例項,google_firestore_database 就會發生錯誤。

專案的預設 Cloud Firestore 例項佈建完成後,您就無法「重新佈建」或變更位置。請注意,已佈建資料庫例項處於 Datastore 模式,這表示 Firebase SDK、驗證或 Firebase Security Rules 無法存取該資料庫。如果您想搭配這些 Firebase 服務使用 Cloud Firestore,就必須清空資料庫,然後在 Google Cloud 控制台中變更資料庫類型。