GCP VPC Network Foundation
Production VPC with subnets, secondary ranges, firewall rules, Cloud Router and Cloud NAT — the network base every GCP workload sits on.
Verification
Plan-validatedPassed: module logic verified on a mocked plan — inputs, validation rules, conditional creation and outputs resolve (no real provider, no cloud).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan: findings disclosed (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
gcp-vpc
Production VPC with subnets, secondary ranges, firewall rules, Cloud Router
and Cloud NAT — the network base every GCP workload sits on. Works with
Terraform and OpenTofu (>= 1.6), Google provider >= 7.0, < 8.0.
Secure defaults:
- Custom-mode network (no auto subnets), Private Google Access on per subnet
- VPC flow logs on by default (5-min aggregation, 50% sampling, all metadata)
- No public SSH: baseline rule allows SSH only from Google's IAP range
(
35.235.240.0/20); pair withgcloud compute ssh --tunnel-through-iap - Allow-internal baseline covers secondary ranges, so GKE pod-to-pod works
- Cloud NAT (auto-allocated IPs, error logging) per region — private instances get egress without external IPs
- Firewall rule logging on by default; every rule must be explicitly allow XOR deny
Usage
module "vpc" {
source = "./gcp-vpc"
project_id = "my-project-123456"
network_name = "prod-vpc"
subnets = {
"app-us-central1" = {
region = "us-central1"
ip_cidr_range = "10.10.0.0/20"
secondary_ip_ranges = {
pods = "10.20.0.0/16"
services = "10.30.0.0/20"
}
}
}
firewall_rules = {
"prod-vpc-allow-https" = {
source_ranges = ["0.0.0.0/0"]
target_tags = ["https-server"]
allow = [{ protocol = "tcp", ports = ["443"] }]
}
}
nat_regions = ["us-central1"]
iap_ssh_target_tags = ["ssh-via-iap"]
}
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
project_id | string | — | GCP project ID (required) |
network_name | string | — | VPC name; prefix for routers/NATs/baseline rules (required) |
description | string | "Managed by Terraform…" | Network description |
routing_mode | string | "GLOBAL" | REGIONAL or GLOBAL |
mtu | number | 1460 | 1300-8896 (8896 = jumbo frames) |
delete_default_routes_on_create | bool | false | Drop the default internet route at creation |
subnets | map(object) | {} | Subnets keyed by name: region, CIDR, secondary ranges, flow-log knobs |
firewall_rules | map(object) | {} | Custom rules keyed by name; exactly one of allow/deny each |
allow_internal | bool | true | Baseline allow between all subnet (incl. secondary) ranges |
allow_iap_ssh | bool | true | Baseline SSH-from-IAP-only rule |
iap_ssh_target_tags | list(string) | [] | Tags targeted by the IAP SSH rule (empty = whole network) |
nat_regions | set(string) | [] | Regions that get Cloud Router + Cloud NAT |
nat_min_ports_per_vm | number | 64 | Minimum NAT ports per VM |
Outputs
network_id, network_name, network_self_link, subnet_ids,
subnet_self_links, subnet_regions, subnet_cidrs,
subnet_secondary_ranges, router_ids, nat_ids.
Requirements
- Terraform or OpenTofu
>= 1.6 hashicorp/google>= 7.0, < 8.0
Notes for integrators:
subnet_secondary_rangesis shaped to feed straight into GKE (cluster_secondary_range_name/services_secondary_range_name).- Cloud NAT here uses
AUTO_ONLYIP allocation and NATs all subnet ranges in the region; bring static NAT IPs in a wrapper if you need allowlisting. - If you set
delete_default_routes_on_create = true, nothing in the VPC can reach the internet (even via NAT) until you add a default route back.
Verification
Static-validated (fmt, validate, tflint). Live apply/destroy testing pending cloud sandbox availability — see catalog status.
License
Commercial — IaC Bazaar EULA. © IaC Bazaar. Original work (not derived from a third-party module).