Architecture: Production VPC Topology
Scenario
In a production environment, you never use the `default` VPC network. You need a custom VPC with strict boundaries. You will build a foundational networking stack for a 3-tier application. This includes a custom VPC network, two regional subnets (web and database), a Cloud Router + Cloud NAT for secure outbound internet access, and firewall rules that only allow SSH via Identity-Aware Proxy (IAP) rather than the public internet.
- Provision a custom google_compute_network.
- Provision google_compute_subnetwork resources for "web" and "db", enforcing private_ip_google_access = true.
- Deploy a google_compute_router and google_compute_router_nat mapping to all subnets in the region.
- Create a google_compute_firewall allowing ingress on TCP 22 only from Google's IAP IP range (35.235.240.0/20).
- Deploy a test Compute Engine instance in the web subnet with no public IP to verify the NAT and IAP configurations.
Additional Context
Identity-Aware Proxy (IAP) TCP Forwarding: Bastion hosts are outdated. GCP allows you to SSH into completely private VMs by tunneling the TCP connection through Google's IAM-secured proxy. To make this work, your VPC firewall must allow ingress on port 22 from `35.235.240.0/20` (the IP blocks used by IAP).
Private Google Access: If a VM has no external IP address, it normally cannot reach Google APIs (like Cloud Storage or the Artifact Registry). Turning on `private_ip_google_access` on the subnet routes requests for Google services internally through the VPC backbone.
variables.tf
variable "project_id" { type = string }
variable "gcp_region" { type = string; default = "us-central1" }main.tf
provider "google" {
project = var.project_id
region = var.gcp_region
}
# 1. Base Network
resource "google_compute_network" "prod_vpc" {
name = "prod-network"
auto_create_subnetworks = false
}
# 2. Subnets
resource "google_compute_subnetwork" "web_tier" {
name = "web-subnet"
network = google_compute_network.prod_vpc.id
region = var.gcp_region
cidr_range = "10.10.10.0/24"
private_ip_google_access = true
}
resource "google_compute_subnetwork" "db_tier" {
name = "db-subnet"
network = google_compute_network.prod_vpc.id
region = var.gcp_region
cidr_range = "10.10.20.0/24"
private_ip_google_access = true
}
# 3. Secure Egress (NAT)
resource "google_compute_router" "prod_router" {
name = "prod-router"
network = google_compute_network.prod_vpc.id
}
resource "google_compute_router_nat" "prod_nat" {
name = "prod-nat"
router = google_compute_router.prod_router.name
region = google_compute_router.prod_router.region
nat_ip_allocate_option = "AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
}
# 4. Ingress Security (IAP Firewall)
resource "google_compute_firewall" "allow_iap_ssh" {
name = "allow-ssh-from-iap"
network = google_compute_network.prod_vpc.id
# GCP IAP IP range
source_ranges = ["35.235.240.0/20"]
allow {
protocol = "tcp"
ports = ["22"]
}
}
# 5. Test Workload (Private VM)
resource "google_compute_instance" "test_vm" {
name = "web-test-01"
machine_type = "e2-micro"
zone = "${var.gcp_region}-a"
boot_disk {
initialize_params { image = "debian-cloud/debian-11" }
}
network_interface {
network = google_compute_network.prod_vpc.id
subnetwork = google_compute_subnetwork.web_tier.id
# No access_config = no public IP!
}
}Workflow Commands
terraform init
terraform apply -var="project_id=my-gcp-project-123"
# Connect to the private VM securely using IAP
gcloud compute ssh web-test-01 \
--zone=us-central1-a \
--tunnel-through-iap
# Inside the VM, confirm outbound internet via NAT works
# curl https://ifconfig.me
terraform destroy -var="project_id=my-gcp-project-123"
