Add comprehensive Terraform infrastructure with Firebase automation

- Create Firebase project, web app, and Firestore database
- Automate Firebase Authentication with email templates
- Configure security rules for user data isolation
- Support Cloud Run and App Engine hosting options
- Add professional email templates for password reset and verification
- Include deployment scripts and comprehensive documentation
- Implement service accounts with minimal required permissions
- Add Docker configuration for containerized deployment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-27 15:46:43 -07:00
parent 2b5bef1a28
commit fa2bbad5ba
17 changed files with 1905 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
# Enable App Engine Admin API
resource "google_project_service" "appengine" {
project = var.gcp_project_id
service = "appengine.googleapis.com"
}
# App Engine Application
resource "google_app_engine_application" "app" {
project = var.gcp_project_id
location_id = var.gcp_region
depends_on = [google_project_service.appengine]
}
# App Engine Service for Flask app
resource "google_app_engine_standard_app_version" "flask_app" {
project = var.gcp_project_id
service = "default"
version_id = "${var.app_name}-v1"
runtime = "python311"
entrypoint {
command = "gunicorn -b :$PORT app:app"
}
deployment {
zip {
source_url = google_storage_bucket_object.app_source_zip.output_uri
}
}
env_variables = {
FLASK_SECRET_KEY = var.flask_secret_key
FIREBASE_PROJECT_ID = var.firebase_project_id
GOOGLE_APPLICATION_CREDENTIALS = "/etc/secrets/service-account.json"
FILEVINE_CLIENT_ID = var.filevine_client_id
FILEVINE_CLIENT_SECRET = var.filevine_client_secret
FILEVINE_PERSONAL_ACCESS_TOKEN = var.filevine_pat
FILEVINE_ORG_ID = var.filevine_org_id
FILEVINE_USER_ID = var.filevine_user_id
}
# Service account
service_account = var.service_account_email
# Resources
resources {
cpu = 1
memory_gb = 0.5
disk_gb = 0.5
}
# Automatic scaling
automatic_scaling {
min_idle_instances = 0
max_idle_instances = 1
min_pending_latency = "automatic"
max_pending_latency = "automatic"
max_concurrent_requests = 80
}
# Health check
health_check {
enable_health_check = true
check_path = "/"
}
depends_on = [
google_storage_bucket_object.app_source_zip,
google_secret_manager_secret_version.service_account_key
]
}
# Make App Engine service publicly accessible
resource "google_app_engine_firewall_rule" "allow_all" {
project = var.gcp_project_id
action = "ALLOW"
priority = "1"
source_range = "*"
}
# Cloud Storage bucket for app source code
resource "google_storage_bucket" "app_source" {
name = "${var.app_name}-source-${var.gcp_project_id}"
location = var.gcp_region
force_destroy = true
uniform_bucket_level_access = true
}
# Upload app source code
resource "google_storage_bucket_object" "app_source_zip" {
name = "app-source.zip"
bucket = google_storage_bucket.app_source.name
source = var.app_source_zip_path
}
# Store service account key in Secret Manager
resource "google_secret_manager_secret" "service_account_key" {
project = var.gcp_project_id
secret_id = "${var.app_name}-service-account-key"
replication {
automatic = true
}
}
resource "google_secret_manager_secret_version" "service_account_key" {
secret = google_secret_manager_secret.service_account_key.id
secret_data = var.service_account_key_data
}
# Output the app URL
output "app_url" {
description = "App Engine application URL"
value = "https://${google_app_engine_application.app.default_hostname}"
}

View File

@@ -0,0 +1,71 @@
variable "app_name" {
description = "Name of the application"
type = string
}
variable "gcp_project_id" {
description = "GCP Project ID"
type = string
}
variable "gcp_region" {
description = "GCP region"
type = string
}
variable "app_source_zip_path" {
description = "Path to the app source code zip file"
type = string
}
variable "firebase_project_id" {
description = "Firebase project ID"
type = string
}
variable "flask_secret_key" {
description = "Flask secret key"
type = string
sensitive = true
}
variable "service_account_email" {
description = "Service account email for the App Engine service"
type = string
}
variable "service_account_key_data" {
description = "Service account key JSON data"
type = string
sensitive = true
}
variable "filevine_client_id" {
description = "Filevine client ID"
type = string
sensitive = true
}
variable "filevine_client_secret" {
description = "Filevine client secret"
type = string
sensitive = true
}
variable "filevine_pat" {
description = "Filevine personal access token"
type = string
sensitive = true
}
variable "filevine_org_id" {
description = "Filevine organization ID"
type = string
sensitive = true
}
variable "filevine_user_id" {
description = "Filevine user ID"
type = string
sensitive = true
}

View File

@@ -0,0 +1,144 @@
# Cloud Run Service for Flask App
resource "google_cloud_run_service" "flask_app" {
name = "${var.app_name}-service"
location = var.gcp_region
template {
spec {
containers {
image = var.container_image
# Environment variables for the Flask app
env {
name = "FLASK_SECRET_KEY"
value = var.flask_secret_key
}
env {
name = "FIREBASE_PROJECT_ID"
value = var.firebase_project_id
}
env {
name = "GOOGLE_APPLICATION_CREDENTIALS"
value = "/etc/secrets/service-account.json"
}
# Filevine API credentials
env {
name = "FILEVINE_CLIENT_ID"
value = var.filevine_client_id
}
env {
name = "FILEVINE_CLIENT_SECRET"
value = var.filevine_client_secret
}
env {
name = "FILEVINE_PERSONAL_ACCESS_TOKEN"
value = var.filevine_pat
}
env {
name = "FILEVINE_ORG_ID"
value = var.filevine_org_id
}
env {
name = "FILEVINE_USER_ID"
value = var.filevine_user_id
}
# Memory and CPU limits
resources {
limits = {
cpu = "1000m"
memory = "512Mi"
}
}
# Mount service account key
volume_mount {
name = "service-account-key"
mount_path = "/etc/secrets"
read_only = true
}
}
# Service account for the container
service_account_name = var.service_account_email
# Volumes
volumes {
name = "service-account-key"
secret {
secret_name = google_secret_manager_secret.service_account_key.secret_id
items {
key = "latest"
path = "service-account.json"
}
}
}
# Allow unauthenticated access
container_concurrency = 100
timeout_seconds = 300
}
# Traffic settings
metadata {
annotations = {
"autoscaling.knative.dev/maxScale" = "10"
"autoscaling.knative.dev/minScale" = "1"
"run.googleapis.com/ingress" = "all"
}
}
}
traffic {
percent = 100
latest_revision = true
}
depends_on = [google_secret_manager_secret_version.service_account_key]
}
# Make Cloud Run service publicly accessible
resource "google_cloud_run_service_iam_member" "public" {
location = google_cloud_run_service.flask_app.location
project = google_cloud_run_service.flask_app.project
service = google_cloud_run_service.flask_app.name
role = "roles/run.invoker"
member = "allUsers"
}
# Store service account key in Secret Manager
resource "google_secret_manager_secret" "service_account_key" {
project = var.gcp_project_id
secret_id = "${var.app_name}-service-account-key"
replication {
automatic = true
}
}
resource "google_secret_manager_secret_version" "service_account_key" {
secret = google_secret_manager_secret.service_account_key.id
secret_data = var.service_account_key_data
}
# Cloud Storage bucket for container storage (if needed)
resource "google_storage_bucket" "app_storage" {
name = "${var.app_name}-storage-${var.gcp_project_id}"
location = var.gcp_region
force_destroy = true
uniform_bucket_level_access = true
}
# Output the service URL
output "service_url" {
description = "Cloud Run service URL"
value = google_cloud_run_service.flask_app.status[0].url
}

View File

@@ -0,0 +1,71 @@
variable "app_name" {
description = "Name of the application"
type = string
}
variable "gcp_project_id" {
description = "GCP Project ID"
type = string
}
variable "gcp_region" {
description = "GCP region"
type = string
}
variable "container_image" {
description = "Docker image for the Flask app"
type = string
}
variable "firebase_project_id" {
description = "Firebase project ID"
type = string
}
variable "flask_secret_key" {
description = "Flask secret key"
type = string
sensitive = true
}
variable "service_account_email" {
description = "Service account email for the Cloud Run service"
type = string
}
variable "service_account_key_data" {
description = "Service account key JSON data"
type = string
sensitive = true
}
variable "filevine_client_id" {
description = "Filevine client ID"
type = string
sensitive = true
}
variable "filevine_client_secret" {
description = "Filevine client secret"
type = string
sensitive = true
}
variable "filevine_pat" {
description = "Filevine personal access token"
type = string
sensitive = true
}
variable "filevine_org_id" {
description = "Filevine organization ID"
type = string
sensitive = true
}
variable "filevine_user_id" {
description = "Filevine user ID"
type = string
sensitive = true
}