Terraform
1. Overview
All GCP infrastructure is provisioned via Terraform. The configuration follows a module-based approach with per-environment variable files for staging and production. State is managed remotely via Terraform Cloud.
2. Directory Structure
terraform/
├── variables.tf # Common variable definitions
├── outputs.tf # Root outputs
├── main.tf # Module orchestration and backend config
├── environments/
│ ├── staging/
│ │ └── terraform.tfvars
│ └── production/
│ └── terraform.tfvars
└── modules/
├── apphub/ # Application Hub registration
├── artifact-registry/ # Docker image registry
├── cloud-run/ # Cloud Run services
├── firebase/ # Firebase project enablement
├── iam/ # IAM roles, service accounts, and WIF
├── identity-platform/ # Identity Platform tenants and providers
├── kms/ # Cloud KMS keys for encryption
├── load-balancer/ # Cloud Load Balancer (HTTPS)
├── monitoring/ # Cloud Monitoring services and SLOs
├── networking/ # VPC, subnets, connector, and DNS
├── project/ # Empty module; root main.tf owns API enablement
├── pubsub/ # Pub/Sub topics and subscriptions
├── secrets/ # Secret Manager secrets
├── security/ # Cloud Armor WAF and SSL policies
├── spanner/ # Cloud Spanner instance, database, and backups
└── storage/ # Cloud Storage buckets
3. Backend Configuration
# main.tf
terraform {
required_version = ">= 1.7.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 7.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = "~> 7.0"
}
}
backend "remote" {
hostname = "app.terraform.io"
organization = "peaksystems"
workspaces {
name = "gateway"
}
}
}
4. Module Specifications
4.1 Project Module
The project module is intentionally empty today. API enablement and core project configuration live in the root main.tf file so Terraform applies them before dependent modules.
# main.tf (API enablement)
resource "google_project_service" "apis" {
for_each = toset([
"run.googleapis.com",
"spanner.googleapis.com",
"pubsub.googleapis.com",
"secretmanager.googleapis.com",
"artifactregistry.googleapis.com",
"compute.googleapis.com",
"vpcaccess.googleapis.com",
"cloudresourcemanager.googleapis.com",
"firebase.googleapis.com",
"identitytoolkit.googleapis.com",
"monitoring.googleapis.com",
"logging.googleapis.com",
"cloudtrace.googleapis.com",
"cloudkms.googleapis.com",
"iam.googleapis.com",
"apphub.googleapis.com",
"dns.googleapis.com",
"storage.googleapis.com",
])
project = var.project_id
service = each.value
disable_on_destroy = false
}
4.2 Networking Module
Implements the VPC, subnets, serverless VPC access connector, and firewall rules. It also configures Private Google Access via Cloud DNS.
# modules/networking/main.tf
resource "google_compute_network" "vpc" {
name = "gateway-vpc"
auto_create_subnetworks = false
project = var.project_id
}
resource "google_compute_subnetwork" "subnet" {
name = "gateway-subnet"
ip_cidr_range = "10.0.0.0/24"
region = var.region
network = google_compute_network.vpc.id
project = var.project_id
}
resource "google_vpc_access_connector" "connector" {
name = "gateway-vpc-connector"
region = var.region
network = google_compute_network.vpc.name
ip_cidr_range = "10.8.0.0/28"
project = var.project_id
}
# Private Google Access DNS and routes are also configured here
4.3 Cloud Run Module
Deploys microservices using for_each. Services are internal-only by default (accessible via Load Balancer or internal VPC). Includes probes and IAM bindings.
# modules/cloud-run/main.tf
resource "google_cloud_run_v2_service" "service" {
for_each = var.services
name = "gateway-${each.key}"
location = var.region
project = var.project_id
ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
template {
service_account = var.service_accounts[each.key]
vpc_access {
network_interfaces {
network = var.vpc_network_id
subnetwork = var.vpc_subnet_id
tags = ["cloud-run"]
}
egress = "PRIVATE_RANGES_ONLY"
}
containers {
image = each.value.image
startup_probe {
http_get { path = "/health" }
}
liveness_probe {
http_get { path = "/health" }
}
# Environment variables and secrets mapped dynamically
}
}
}
4.4 Spanner Module
Configures the Cloud Spanner instance and database with CMEK encryption and a daily backup schedule.
# modules/spanner/main.tf
resource "google_spanner_instance" "instance" {
name = "gateway-spanner"
config = "regional-${var.region}"
processing_units = var.spanner_processing_units
project = var.project_id
}
resource "google_spanner_database" "database" {
instance = google_spanner_instance.instance.name
name = "gateway-db"
project = var.project_id
database_dialect = "POSTGRESQL"
encryption_config {
kms_key_name = var.kms_key_id
}
}
resource "google_spanner_backup_schedule" "daily" {
instance = google_spanner_instance.instance.name
database = google_spanner_database.database.name
name = "daily-backup"
spec {
cron_spec { text = "0 2 * * *" }
}
}
5. Environment Variables
Staging (terraform.tfvars)
environment = "staging"
project_id = "peak-gateway-staging"
project_number = "" # Set after project creation
region = "us-central1"
spanner_processing_units = 100
cloud_run_deletion_protection = false
microservice_min_instances = 0
microservice_max_instances = 5
microservice_warm_services = []
identity_saml_callback_uris = ["https://peak-gateway-staging.firebaseapp.com/__/auth/handler"]
Production (terraform.tfvars)
environment = "production"
project_id = "peak-gateway-prod"
project_number = "" # Set after project creation
region = "us-central1"
spanner_processing_units = 1000
cloud_run_deletion_protection = true
microservice_min_instances = 1
microservice_max_instances = 20
microservice_warm_services = ["processing", "online-txn"]
identity_saml_callback_uris = ["https://peak-gateway-prod.firebaseapp.com/__/auth/handler"]
6. Deployment Commands
# Initialize with Terraform Cloud
cd terraform
terraform init
# Select workspace/environment is handled via Terraform Cloud or local workspace selection
# To plan/apply for a specific environment using local files:
# Staging
terraform plan -var-file=environments/staging/terraform.tfvars
terraform apply -var-file=environments/staging/terraform.tfvars
# Production
terraform plan -var-file=environments/production/terraform.tfvars
terraform apply -var-file=environments/production/terraform.tfvars