-
-
Save zebreus/906b8870e49586adfe8bd7bbff43f0a8 to your computer and use it in GitHub Desktop.
# firebase.tf https://gist.githubusercontent.com/Zebreus/906b8870e49586adfe8bd7bbff43f0a8/raw/firebase.tf | |
# Terraform configuration for creating a firebase project with firestore, functions and storage | |
# Unfinished | |
terraform { | |
required_providers { | |
google-beta = { | |
source = "hashicorp/google-beta" | |
version = "4.11.0" | |
} | |
null = { | |
version = "~> 3.1.0" | |
} | |
time = { | |
source = "hashicorp/time" | |
version = "0.7.2" | |
} | |
} | |
} | |
variable "billing_account_id" { | |
type = string | |
description = "The id of the associated billing account" | |
nullable = false | |
} | |
variable "project_id" { | |
type = string | |
description = "The id of the created project" | |
nullable = false | |
} | |
variable "project_name" { | |
type = string | |
description = "The name of the created project" | |
nullable = false | |
} | |
variable "region" { | |
type = string | |
description = "The region to create the project in" | |
default = "europe-west1" | |
nullable = false | |
} | |
variable "zone" { | |
type = string | |
description = "The zone to create the project in" | |
default = "europe-west1-b" | |
nullable = false | |
} | |
variable "location" { | |
type = string | |
description = "The location to create the project in" | |
default = "europe-west" | |
nullable = false | |
} | |
locals { | |
bucket_location = "EUROPE-WEST1" | |
} | |
# Basic provider | |
provider "google-beta" { | |
alias = "gcloud-user" | |
region = var.region | |
zone = var.zone | |
} | |
data "google_billing_account" "account" { | |
provider = google-beta.gcloud-user | |
billing_account = var.billing_account_id | |
} | |
data "google_client_config" "gcloud-user" { | |
provider = google-beta.gcloud-user | |
# depends_on = [ | |
# google_service_account.service_account | |
# ] | |
} | |
data "google_client_openid_userinfo" "gcloud-user" { | |
provider = google-beta.gcloud-user | |
} | |
// Create new google cloud project with service account | |
resource "google_project" "default" { | |
provider = google-beta.gcloud-user | |
project_id = var.project_id | |
name = var.project_name | |
billing_account = data.google_billing_account.account.id | |
} | |
resource "google_service_account" "service_account" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
account_id = "terraform" | |
display_name = "Terraform" | |
} | |
# Allow your user to create a access token | |
resource "google_service_account_iam_member" "grant-token-iam" { | |
provider = google-beta.gcloud-user | |
service_account_id = google_service_account.service_account.id | |
role = "roles/iam.serviceAccountTokenCreator" | |
member = "user:${data.google_client_openid_userinfo.gcloud-user.email}" | |
} | |
resource "time_sleep" "delay_token_creation" { | |
depends_on = [ | |
google_service_account_iam_member.grant-token-iam, | |
google_service_account.service_account, | |
google_project_iam_member.firebase-admin-iam, | |
google_project_iam_member.service-usage-admin-iam, | |
google_project_iam_member.appengine-admin-iam, | |
google_project_iam_member.appengine-creator-iam, | |
google_project_iam_member.editor-iam | |
] | |
create_duration = "30s" | |
} | |
# Create access token | |
data "google_service_account_access_token" "default" { | |
provider = google-beta.gcloud-user | |
# project = google_project.default.project_id | |
target_service_account = google_service_account.service_account.email | |
scopes = ["userinfo-email", "cloud-platform"] | |
lifetime = "300s" | |
depends_on = [ | |
google_service_account_iam_member.grant-token-iam, | |
google_service_account.service_account, | |
google_project_iam_member.firebase-admin-iam, | |
google_project_iam_member.service-usage-admin-iam, | |
google_project_iam_member.appengine-admin-iam, | |
google_project_iam_member.appengine-creator-iam, | |
google_project_iam_member.editor-iam, | |
time_sleep.delay_token_creation | |
] | |
} | |
# Give some roles to the service account | |
resource "google_project_iam_member" "firebase-admin-iam" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/firebase.admin" | |
member = "serviceAccount:${google_service_account.service_account.email}" | |
} | |
resource "google_project_iam_member" "service-usage-admin-iam" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/serviceusage.serviceUsageAdmin" | |
member = "serviceAccount:${google_service_account.service_account.email}" | |
} | |
resource "google_project_iam_member" "appengine-admin-iam" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/appengine.appAdmin" | |
member = "serviceAccount:${google_service_account.service_account.email}" | |
} | |
resource "google_project_iam_member" "appengine-creator-iam" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/appengine.appCreator" | |
member = "serviceAccount:${google_service_account.service_account.email}" | |
} | |
resource "google_project_iam_member" "editor-iam" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/editor" | |
member = "serviceAccount:${google_service_account.service_account.email}" | |
} | |
# Create provider with service account | |
resource "google_service_account_key" "mykey" { | |
provider = google-beta.gcloud-user | |
service_account_id = google_service_account.service_account.id | |
# Wait for the account being added to roles | |
depends_on = [ | |
google_project_iam_member.firebase-admin-iam, | |
google_project_iam_member.service-usage-admin-iam, | |
] | |
} | |
provider "google-beta" { | |
alias = "service-account" | |
project = google_project.default.project_id | |
region = var.region | |
zone = var.zone | |
# impersonate_service_account = google_service_account.service_account.email | |
# credentials = base64decode(google_service_account_key.mykey.private_key) | |
access_token = data.google_service_account_access_token.default.access_token | |
} | |
# Activate all required apis | |
resource "google_project_service" "serviceusage" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
service = "serviceusage.googleapis.com" | |
disable_dependent_services = true | |
depends_on = [ | |
] | |
} | |
resource "google_project_service" "firebase" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "firebase.googleapis.com" | |
disable_dependent_services = true | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "firestore" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "firestore.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "firebasestorage" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "firebasestorage.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "cloudresourcemanager" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "cloudresourcemanager.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "identitytoolkit" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "identitytoolkit.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "compute" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "compute.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "container_registry" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "containerregistry.googleapis.com" | |
disable_dependent_services = true | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "cloud_run" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "run.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
resource "google_project_service" "cloud_build" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
service = "cloudbuild.googleapis.com" | |
depends_on = [ | |
google_project_service.serviceusage | |
] | |
} | |
# Create firebase project | |
resource "google_firebase_project" "default" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
depends_on = [ | |
google_project_service.firebase | |
] | |
} | |
# Create firebase web app | |
resource "google_firebase_web_app" "basic" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
display_name = "${var.project_name} App" | |
depends_on = [ | |
google_firebase_project.default | |
] | |
} | |
data "google_firebase_web_app_config" "basic" { | |
provider = google-beta.service-account | |
web_app_id = google_firebase_web_app.basic.app_id | |
} | |
# Create firestore database | |
resource "google_app_engine_application" "app" { | |
provider = google-beta.service-account | |
# provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
location_id = var.location | |
database_type = "CLOUD_FIRESTORE" | |
depends_on = [ | |
google_project_iam_member.appengine-admin-iam, | |
google_project_iam_member.appengine-creator-iam, | |
google_project_service.firestore | |
] | |
} | |
# Create a bucket for backups | |
resource "google_storage_bucket" "backup" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
name = "${google_project.default.project_id}-backup" | |
location = local.bucket_location | |
} | |
# Create admin-sdk service account | |
resource "google_service_account" "admin_sdk" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
account_id = "firebase-adminsdk-ouwu6" | |
display_name = "firebase-adminsdk" | |
} | |
resource "google_project_iam_member" "admin-sdk-token-creator" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/iam.serviceAccountTokenCreator" | |
member = "serviceAccount:${google_service_account.admin_sdk.email}" | |
} | |
resource "google_project_iam_member" "admin-sdk-agent" { | |
provider = google-beta.gcloud-user | |
project = google_project.default.project_id | |
role = "roles/firebase.sdkAdminServiceAgent" | |
member = "serviceAccount:${google_service_account.admin_sdk.email}" | |
} | |
resource "google_service_account_key" "admin_sdk" { | |
provider = google-beta.gcloud-user | |
service_account_id = google_service_account.service_account.id | |
# Wait for the account being added to roles | |
depends_on = [ | |
google_project_iam_member.admin-sdk-token-creator, | |
google_project_iam_member.admin-sdk-agent, | |
] | |
} | |
# Create firebase storage | |
resource "null_resource" "activate_storage" { | |
triggers = { | |
bucket = data.google_firebase_web_app_config.basic.storage_bucket | |
} | |
provisioner "local-exec" { | |
command = "curl -X POST -H 'Authorization: Bearer ${nonsensitive(data.google_service_account_access_token.default.access_token)}' -H 'Content-Type: application/json' 'https://firebasestorage.googleapis.com/v1beta/projects/${google_project.default.project_id}/buckets/${data.google_firebase_web_app_config.basic.storage_bucket}:addFirebase'" | |
interpreter = ["sh", "-c"] | |
} | |
depends_on = [ | |
google_firebase_web_app.basic, | |
google_project_service.firebasestorage | |
] | |
} | |
# Enable authentication service | |
resource "google_identity_platform_config" "identity_platform_config" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
autodelete_anonymous_users = true | |
depends_on = [ | |
google_firebase_web_app.basic, | |
google_project_service.identitytoolkit | |
] | |
} | |
resource "google_identity_platform_project_default_config" "identity_project_config" { | |
provider = google-beta.service-account | |
project = google_project.default.project_id | |
sign_in { | |
allow_duplicate_emails = false | |
email { | |
enabled = true | |
password_required = true | |
} | |
} | |
depends_on =[google_identity_platform_config.identity_platform_config] | |
} | |
# Write secrets to local file | |
resource "local_file" "firebase_config" { | |
content = jsonencode({ | |
firebase = { | |
appId = google_firebase_web_app.basic.app_id | |
apiKey = data.google_firebase_web_app_config.basic.api_key | |
authDomain = data.google_firebase_web_app_config.basic.auth_domain | |
databaseURL = lookup(data.google_firebase_web_app_config.basic, "database_url", "") | |
storageBucket = lookup(data.google_firebase_web_app_config.basic, "storage_bucket", "") | |
messagingSenderId = lookup(data.google_firebase_web_app_config.basic, "messaging_sender_id", "") | |
measurementId = lookup(data.google_firebase_web_app_config.basic, "measurement_id", "") | |
} | |
}) | |
filename = "${path.module}/firebase-config.json" | |
depends_on = [ | |
google_firebase_web_app.basic | |
] | |
} | |
resource "local_file" "secrets_file" { | |
content = jsonencode({ | |
private = { | |
serviceAccount = jsondecode(base64decode(google_service_account_key.admin_sdk.private_key)) | |
firebase = { | |
backupBucket = google_storage_bucket.backup.name | |
} | |
} | |
public = { | |
firebase = { | |
projectId = google_project.default.project_id | |
appId = google_firebase_web_app.basic.app_id | |
apiKey = data.google_firebase_web_app_config.basic.api_key | |
authDomain = data.google_firebase_web_app_config.basic.auth_domain | |
databaseURL = lookup(data.google_firebase_web_app_config.basic, "database_url", "") | |
storageBucket = lookup(data.google_firebase_web_app_config.basic, "storage_bucket", "") | |
messagingSenderId = lookup(data.google_firebase_web_app_config.basic, "messaging_sender_id", "") | |
measurementId = lookup(data.google_firebase_web_app_config.basic, "measurement_id", "") | |
} | |
} | |
}) | |
filename = "${path.module}/secrets.json" | |
depends_on = [ | |
google_firebase_web_app.basic | |
] | |
} | |
resource "local_file" "firebaserc" { | |
content = jsonencode({ | |
projects = { | |
development = google_project.default.project_id | |
production = google_project.default.project_id | |
} | |
}) | |
filename = "${path.module}/.firebaserc" | |
depends_on = [ | |
google_project.default | |
] | |
} | |
resource "local_file" "admin_config" { | |
content = base64decode(google_service_account_key.mykey.private_key) | |
filename = "${path.module}/admin-config.json" | |
depends_on = [ | |
google_service_account_key.mykey, | |
google_firebase_web_app.basic | |
] | |
} |
Neat solution! I added it to the gist.
I am curious to know how you figured out that the config was missing?
@zebreus I figured Identity Platform was one of the APIs independent from firebase, so you can open it in the GCP console and see what is missing. And you can find what can be configured in the terraform doc.
Just wondering if anyone has run into this issue with the latest version of this gist:
╷
│ Error: Invalid resource type
│
│ on main.tf line 363, in resource "google_identity_platform_config" "identity_platform_config":
│ 363: resource "google_identity_platform_config" "identity_platform_config" {
│
│ The provider hashicorp/google-beta does not support resource type "google_identity_platform_config".
I pulled the google_identity_platform_config.identity_platform_config
resource into my own script, dropped the provider = google-beta
instruction (as of v4.66.0, you don't need the beta provider), and it worked fine for me.
This gist is super helpful, thank you! FYI, setting authorized domains is now supported: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/identity_platform_config#authorized_domains
@zebreus After some trial and error, I did find a way to do this. Basically, it is not enough to just activate the identitytoolkit api, you also need to create a default config and then activate the sign in methods you want to enable. Here is the complete code :
Here I am enabling the email/password login.
This removed the need to manually enable the api. However, there are still some manual steps to do which are not available in terraform (at least I did not find a way) :
So, not perfect, but the provider is still in beta, so I guess we'll get there.