Firebase 现在提供 Terraform 支持。如果您所在的团队想要用一套标准化的流程自动创建预配了特定资源并启用了相关服务的 Firebase 项目,那么将 Terraform 与 Firebase 搭配使用会非常有用。
若要将 Terraform 与 Firebase 搭配使用,需完成下面的基本工作流程:
创建和自定义 Terraform 配置文件(一个
.tf
文件),用于指定您要预配的基础架构(即要预配的资源和要启用的服务)。使用与 Terraform 关联的 gcloud CLI 命令来预配
.tf
文件中指定的基础架构。
您可以使用 Terraform 和 Firebase 执行哪些操作?
本指南中的通用工作流示例会创建一个新的 Firebase 项目来提供 Android 应用。不过,您可以使用 Terraform 执行更多操作,例如:
使用 Terraform 删除和修改现有基础架构。
使用 Terraform 管理产品专用配置和任务,如:
- 启用 Firebase Authentication 登录提供方。
- 创建 Cloud Storage 存储桶或数据库实例并为其部署 Firebase Security Rules。
您可以使用标准 Terraform 配置文件和命令来完成所有这些任务。另外,为了帮助您完成这些任务,我们针对几种常见的使用场景提供了 Terraform 示例配置文件。
将 Terraform 与 Firebase 搭配使用的通用工作流
前提条件
本指南介绍如何将 Terraform 与 Firebase 搭配使用,因此假定您已基本掌握 Terraform 的使用。在开始此工作流之前,请确保您已满足以下前提条件。
安装 Terraform 并通过官方教程熟悉 Terraform 的使用。
安装 Google Cloud CLI (gcloud CLI)。使用用户账号或服务账号登录。
查看针对用户账号和服务账号的要求
- 如果使用用户账号,您必须已接受 Firebase 服务条款 (TOS)。如果您可以在 Firebase 控制台中查看 Firebase 项目,则表示您已接受 Firebase 服务条款 (ToS)
- 为了让 Terraform 能够执行某些操作(例如,创建项目),还必须满足以下条件:
- 用户账号或服务账号必须拥有允许执行这些操作的 IAM 权限。
- 如果用户账号或服务账号属于某个 Google Cloud 组织,那么该组织的政策必须允许该账号执行这些操作。
第 1 步:创建和自定义 Terraform 配置文件
Terraform 配置文件需要有两个主要构成部分(详见下文):
设置您的 provider
无论涉及哪些 Firebase 产品或服务,都需要进行 provider
设置。
在您的本地目录中创建一个 Terraform 配置文件(如
main.tf
文件)。在本指南中,您将使用此配置文件来指定
provider
设置以及您希望 Terraform 创建的所有基础架构。但请注意,您可以自行选择添加该提供方设置的方法。了解添加
provider
设置的各种方法您可以通过以下方法将
provider
设置添加到 Terraform 配置的其余部分:方法 1:在同一个 Terraform
.tf
配置文件的开头部分添加该设置(如本指南所示)。- 如果您刚开始使用 Terraform,或者只是想尝试将 Terraform 与 Firebase 搭配使用的效果,则可以使用此方法。
方法 2:在一个单独的
.tf
文件(如provider.tf
文件)中添加该设置,该文件与您在其中指定要创建的基础架构的.tf
文件(如main.tf
文件)彼此区分。- 如果您所在的团队规模较大且需要实施标准化设置,则可以使用此方法。
- 在这种情况下,运行 Terraform 命令时,
provider.tf
文件和main.tf
文件必须位于同一目录中。
在
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 }
详细了解将 Terraform 与 Firebase 搭配使用时涉及的不同类型的项目相关特性(包括本指南中称为“配额检查项目”的内容)。
继续下一部分内容,完成配置文件并指定要创建的基础架构。
使用 resource
块指定要创建的基础架构
在 Terraform 配置文件(在本指南中,即为 main.tf
文件)中,需指定您想要 Terraform 创建的所有基础架构(即要预配的所有资源和要启用的所有服务)。本指南中提供了支持 Terraform 的所有 Firebase 资源的完整列表。
打开
main.tf
文件。在
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, ] }
下面是此示例配置文件的详尽注释版本
如果您还不熟悉将项目和应用作为资源进行部署的基础架构,请参阅以下文档:
- 了解 Firebase 项目
- Firebase 项目管理参考文档
# 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 文档。
如果这是您首次在该目录中运行 Terraform 命令,您需要初始化配置目录并安装 Google Terraform 提供方。为此,请运行以下命令:
terraform init
运行以下命令,创建
main.tf
文件中指定的基础架构:terraform apply
通过以下方法,确认所有内容均已按预期预配或启用:
方法 1:运行以下命令,查看在终端中显示的配置输出:
terraform show
方法 2:在 Firebase 控制台中查看您的 Firebase 项目。
支持 Terraform 的 Firebase 资源
以下 Firebase 和 Google 资源现在支持 Terraform。我们还在不断添加更多提供该支持的资源!因此,即便您现在没有看到自己想要通过 Terraform 管理的资源,您可以隔一段时间再来查看,也可以在 GitHub 代码库中提交问题,申请加速对该资源的支持。
Firebase 项目和应用管理
google_firebase_project
- 在现有 Google Cloud 项目中启用 Firebase 服务Firebase 应用
google_firebase_apple_app
- 创建或管理在 Apple 平台上运行的 Firebase 应用google_firebase_android_app
- 创建或管理在 Android 平台上运行的 Firebase 应用google_firebase_web_app
- 创建或管理 Web 版 Firebase 应用
Firebase Authentication
google_identity_platform_config
- 启用 Google Cloud Identity Platform (GCIP)(即 Firebase Authentication 的后端),并提供项目级身份验证设置若要通过 Terraform 配置 Firebase Authentication,必须启用 GCIP。请务必查看
.tf
示例文件,了解如何设置 Firebase Authentication。将要通过 Terraform 启用 GCIP 和/或 Firebase Authentication 的项目必须采用 Blaze 定价方案(也就是说,该项目必须具有关联的 Cloud Billing 账号)。您可以通过在
google_project
资源中设置billing_account
属性以编程方式关联此账号。此资源还支持更多配置,例如本地登录方法(如匿名、电子邮件地址/密码和电话身份验证),以及屏蔽函数和授权网域。
google_identity_platform_default_supported_idp_config
- 配置常见的联合身份提供方(例如 Google、Facebook 或 Apple)identity_platform_oauth_idp_config
- 配置任意 OAuth 身份提供方 (IdP) 来源google_identity_platform_inbound_saml_config
- 配置 SAML 集成
暂不支持以下功能:
- 通过 Terraform 配置多重身份验证 (MFA)
Firebase Realtime Database
google_firebase_database_instance
— 创建一个 Realtime Database 实例
暂不支持以下功能:
- 通过 Terraform 部署 Firebase Realtime Database Security Rules(了解如何使用其他工具,包括通过编程方式,来部署这些Rules)
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 Firestore 和 Cloud Storage)
请注意,Firebase Realtime Database 的 Firebase Security Rules使用的是不同的预配系统。
google_firebaserules_ruleset
- 定义适用于 Cloud Firestore 实例或 Cloud Storage 存储桶的 Firebase Security Rulesgoogle_firebaserules_release
- 将特定规则集部署到 Cloud Firestore 实例或 Cloud Storage 存储桶
Firebase App Check
google_firebase_app_check_service_config
- 为服务启用 App Check 强制执行google_firebase_app_check_app_attest_config
- 向 App Attest 提供方注册 Apple 平台应用google_firebase_app_check_device_check_config
- 向 DeviceCheck 提供方注册 Apple 平台应用google_firebase_app_check_play_integrity_config
- 向 Play Integrity 提供方注册 Android 应用google_firebase_app_check_recaptcha_enterprise_config
- 向 reCAPTCHA Enterprise 提供方注册 Web 应用google_firebase_app_check_recaptcha_v3_config
- 向 reCAPTCHA v3 提供方注册 Web 应用google_firebase_app_check_debug_token
- 使用调试令牌进行测试
Firebase Extensions
google_firebase_extensions_instance
- 安装或更新 Firebase Extension 的实例
常见使用场景的 Terraform 示例配置文件
设置 Firebase Authentication with GCIP
此配置会创建一个新的 Google Cloud 项目,将该项目与一个 Cloud Billing 账号关联(若要使用 Firebase Authentication with GCIP,您的项目必须采用 Blaze 定价方案),为项目启用所需的 Firebase 服务,设置 Firebase Authentication with GCIP,并在项目中注册三种不同的应用类型。
请注意,必须启用 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, ] }
预配默认的 Firebase Realtime Database 实例
此配置会创建一个新的 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, ] }
预配多个 Firebase Realtime Database 实例
此配置会创建一个新的 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, ] }
预配默认的 Cloud Firestore 实例
此配置会创建一个新的 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, ] }
这是应包含在名为 firestore.rules
的本地文件中的 Cloud Firestore Security Rules的规则集。
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /some_collection/{document} { allow read, create, update: if request.auth != null; } } }
预配默认的 Cloud Storage 存储桶
预配其他 Cloud Storage 个存储桶
此配置会创建一个新的 Google Cloud 项目,将该项目与一个 Cloud Billing 账号关联(若要使用其他存储桶,您的项目必须采用 Blaze 定价方案),为项目启用所需的 Firebase 服务,预配其他非默认的 Cloud Storage 存储桶,并在项目中注册三种不同的应用类型。
此外,还会为每个 Cloud Storage 存储桶预配 Firebase Security Rules,并将文件上传到其中一个 Cloud Storage 存储桶。
# 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, ] }
这是应包含在名为 storage.rules
的本地文件中的 Cloud Storage Security Rules的规则集。
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /some_folder/{fileName} { allow read, write: if request.auth != null; } } }
使用 Firebase App Check 保护 API 资源
此配置会创建一个新的 Google Cloud 项目,为项目启用 Firebase 服务,并为 Cloud Firestore 设置并启用 Firebase App Check 强制执行,以便只能通过您的 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] }
安装 Firebase Extension 的实例
此配置会创建一个新的 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" } } }
问题排查和常见问题解答
您想要详细了解所有与项目相关的不同属性(如 project
和 user_project_override
)
本指南在涉及“项目”时会用到下面的 Terraform 属性。
resource
块中的project
建议:尽可能在每个
resource
块中添加project
属性如果添加了 project 属性,Terraform 将在 resource 块中的指定项目内创建指定基础架构。本指南相关内容及示例配置文件都是采用这种做法。
请参阅 Terraform 官方文档中有关
project
的内容。provider
块中的user_project_override
若要预配大多数资源,则应使用
user_project_override = true
,这意味着系统会检查您的 Firebase 项目的配额。不过,若要将新项目设置为能够接受配额检查,您需要首先使用user_project_override = false
。请参阅 Terraform 官方文档中有关
user_project_override
的内容。
您收到以下错误:generic::permission_denied: Firebase Tos Not Accepted
。
请确保您用于运行 gcloud CLI 命令的用户账号已接受 Firebase 服务条款 (Firebase ToS)。
您可以使用已登录该用户账号的浏览器尝试在 Firebase 控制台中查看一个现有 Firebase 项目,以进行确认。如果您可以查看现有 Firebase 项目,则表明该用户账号已接受 Firebase 服务条款 (TOS)。
如果您无法查看任何现有 Firebase 项目,则表明该用户账号可能尚未接受 Firebase 服务条款 (TOS)。若要解决此问题,您可以通过 Firebase 控制台创建一个新的 Firebase 项目,并在项目创建过程中接受 Firebase 服务条款 (TOS)。您可以在完成此操作后立即通过控制台中的“项目设置”删除此项目。
您在运行 terraform apply
后收到以下错误:generic::permission_denied: IAM authority does not have the
permission
。
请等待几分钟,然后再次尝试运行 terraform apply
。
资源创建失败,但当您再次运行 terraform apply
,却显示 ALREADY_EXISTS
。
这可能是由于各种系统中的传播延迟造成的。您可以运行 terraform import
,将资源导入 Terraform 状态,以尝试解决此问题。然后,尝试再次运行 terraform apply
。
如需了解如何导入每种资源,请参阅其相应 Terraform 文档的“导入”部分(如 Cloud Firestore 的“导入”文档)。
您在使用 Cloud Firestore 时收到以下错误:Error creating Index: googleapi:
Error 409;...Concurrent access -- try again
如该错误所示,Terraform 可能在尝试同时预配多个索引并/或创建同一个文档,从而遇到并发错误。尝试再次运行 terraform apply
。
您收到以下错误:"you may need to specify 'X-Goog-User-Project' HTTP header for quota and
billing purposes"
。
此错误表示 Terraform 不知道要检查哪个项目的配额。如需进行问题排查,请在 resource
块中检查以下内容:
- 确保为
project
属性指定了值。 - 确保为提供方设置了
user_project_override = true
(无别名),在 Firebase 示例中该提供方为google-beta
。
您在创建新的 Google Cloud 项目时收到错误,表示为该新项目指定的项目 ID 已存在。
项目 ID 已存在的可能原因如下:
与该 ID 关联的项目属于他人。
- 解决方法:选择其他项目 ID。
与该 ID 关联的项目最近被删除(处于软删除状态)。
- 解决方法:如果您确定与该 ID 关联的项目属于您,则可以使用
projects.get
REST API 检查该项目的状态。
- 解决方法:如果您确定与该 ID 关联的项目属于您,则可以使用
与该 ID 关联的项目正确地存在于当前用户下。错误的可能原因是先前的
terraform apply
被中断。- 解决方法:依次运行以下命令:
terraform import google_project.default PROJECT_ID
和
terraform import google_firebase_project.default PROJECT_ID
- 解决方法:依次运行以下命令:
为什么您需要在默认 Cloud Storage 存储桶之前配置默认 Cloud Firestore 实例?
如果您在尝试配置默认 Cloud Firestore 实例之前(通过 google_app_engine_application
)配置了默认的 Cloud Storage 存储桶,那么您会发现默认的 Cloud Firestore 实例已预配。请注意,预配的数据库实例处于 Datastore 模式,这意味着 Firebase SDK、身份验证机制或 Firebase Security Rules无法访问该实例。在这种情况下,如果您希望能够搭配这些 Firebase 服务使用 Cloud Firestore,则需要清空数据库,然后在 Google Cloud 控制台中更改其数据库类型。
您在尝试依次预配 Cloud Storage(通过 google_app_engine_application
)和默认的 Cloud Firestore 实例时收到以下错误:Error: Error creating Database: googleapi: Error 409: Database already
exists. Please use another database_id
。
如果您通过 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 控制台中更改其数据库类型。