Network Automation with Terraform

In a world where a single VPC can span the globe and a single firewall misconfiguration can expose an entire organization, manual configuration through the Cloud Console is not just inefficient—it is dangerous. Clicking through the UI to create subnets, firewall rules, and VPN tunnels works for a lab environment, but in production, you need repeatability, version control, and peer review. This is where Infrastructure as Code (IaC) comes in, and for Google Cloud networking, the tool of choice is Terraform.

Terraform does not execute commands against the Google API in real-time. Instead, you write declarative configuration files (.tf) that describe the desired state of your infrastructure. Terraform compares the desired state against the actual state (stored in a state file) and calculates the minimal set of API calls needed to reconcile the difference. This “plan and apply” model gives you a preview of every change before it happens—eliminating the “I accidentally deleted the production VPC” class of incidents.

The Core Networking Resources
google_compute_network

The VPC itself. You specify the name, the routing mode (regional or global), and whether it is Auto or Custom mode.

resource "google_compute_network" "main" {
  name                    = "prod-vpc"
  auto_create_subnetworks = false
  routing_mode            = "GLOBAL"
}
google_compute_subnetwork

A subnet within the VPC. You specify the region, the primary IP range, and optional secondary ranges for GKE.

resource "google_compute_subnetwork" "us" {
  name          = "prod-us"
  region        = "us-central1"
  network       = google_compute_network.main.id
  ip_cidr_range = "10.1.0.0/24"
}
google_compute_firewall

A VPC firewall rule. Notice how it references the VPC by its Terraform resource name, not a string—this creates an implicit dependency.

resource "google_compute_firewall" "allow_http" {
  name    = "allow-http"
  network = google_compute_network.main.name
  allow {
    protocol = "tcp"
    ports    = ["80", "443"]
  }
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["web"]
}
Dependency Management: The Silent Killer

The most common Terraform mistake in networking is resource ordering. You cannot create a firewall rule before the VPC exists. You cannot create a VPN tunnel before the Cloud Router exists. Terraform handles this through implicit dependencies (when one resource references another’s attribute) and explicit dependencies (using depends_on).

If your terraform apply fails with “Resource not found,” the problem is almost always a missing dependency—Terraform tried to create a resource before its parent existed.

State Management

Terraform’s state file is the single source of truth. In a team environment, you must store it remotely (in a Cloud Storage bucket) with state locking (using Cloud Storage’s object versioning or a backend like gcs).

  1. Remote State: terraform { backend "gcs" { bucket = "my-tf-state" } }
  2. State Locking: Prevents two engineers from running terraform apply simultaneously.
  3. State Drift: If someone manually changes a resource in the Console, Terraform will detect the drift on the next plan and propose reverting it.
Putting it Together: A Pro-Engineer View

Imagine you are the platform engineer for a startup that just raised Series B. You define your entire network in Terraform: a Custom Mode VPC with subnets in three regions, HA VPN tunnels to your on-premises office, Cloud NAT gateways, Hierarchical Firewall Policies, and an Internal HTTPS Load Balancer. Every change goes through a pull request. terraform plan runs in CI and posts the diff as a comment. Only after peer review does terraform apply run. If a new developer needs a subnet in a new region, they add 8 lines of HCL, get it reviewed, and merge. The subnet appears in production 90 seconds later—with zero clicks in the Console.