-
-
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 | |
] | |
} |
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 i was looking at your null resource and how you're authenticating to get a token and then curling the firebase api. i started digging around for ways to create custom resources. have you looked into creating a plugin to extend the google-beta provider. that way you could write more robust crud and state management and lifecycle logic with the go sdk for firebase admin. you should be able to inherit auth from the same instantiation as your parent provider call too.
are you still effing with this? it's cool stuff. it would be really powerful to be able to fully manage firebase projects from code and i don't feel like waiting around for a version that does. i'm going to start hacking on something. let me know if you have any advice or another repo started with something like this.
@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.