Production-grade GKE with Terraform and a Shared VPC
Taking a hand-provisioned GKE estate to 100% infrastructure as code: a Shared VPC, private clusters, an 8-phase rollout and the guardrails that stop a stray destroy. Plus the open-source landing zones I built for GCP, AWS and Azure on the same pattern.
Picture a GKE estate and the network under it, all provisioned by hand. No infrastructure as code, no consistent story across environments, and nothing stopping a stray terraform destroy from taking out the shared network. This is a write-up of rebuilding that into a Shared VPC, private clusters, a modular Terraform codebase, and an eight-phase rollout that never left the system half-managed.
Everything here is the technique, with no internal names or specifics. At the end I link the open-source landing zones I built for GCP, AWS and Azure, so you can read the actual code behind the same pattern.
The starting point
Clusters and network were created through the console and a monolithic, copy-pasted Terraform file. There was no reusable module, no per-environment strategy, and no prevent_destroy on the network. In other words, the one resource you cannot casually recreate, the VPC, was the least protected thing in the project.
The target architecture
- Shared VPC. One host project owns the VPC, subnets, Cloud NAT and firewall. Each environment is a service project attached to it, so the network lives in one place and clusters never own their own VPC.
- Private clusters. Nodes have no public IPs. All egress goes out through Cloud NAT, so the surface facing the internet is one gateway, not every node.
- Workload Identity. Pods authenticate as GCP service accounts without node-level keys to manage or leak.
- Shielded nodes. Secure Boot and Integrity Monitoring on every node.
- Least privilege. A dedicated service account per environment, scoped to what that environment needs.
- Remote state. Terraform state in a GCS backend, not on anyone's laptop.
The rollout, in eight phases
The point of phasing it was to never have a window where the network was half-managed. Each phase left the system in a working state.
- 1. Architecture design. Shared VPC topology, subnet strategy and cluster requirements for four environments.
- 2. Project setup. Projects, enabled APIs, and IAM service accounts with least-privilege bindings.
- 3. Network. Shared VPC host project, subnets, Cloud NAT and firewall rules, all via Terraform.
- 4. Modular Terraform. Refactored from monolithic inline resources to reusable modules; the root config became module calls plus a variable file per environment.
- 5. CI/CD. GitHub Actions:
terraform planon pull request,terraform applyon merge, a separate workflow per environment. - 6. Clusters. All four GKE clusters (dev, stg, prd, sdx) deployed through the pipelines.
- 7. Guardrails.
prevent_destroy = trueon the VPC, subnets and Cloud NAT. - 8. Documentation. Architecture diagrams, runbooks and module docs for handover.
The guardrail that matters most
A prevent_destroy lifecycle block on the VPC, subnets and Cloud NAT makes an accidental terraform destroy of the network fail instead of succeed. The network is the one thing you cannot casually recreate, so it is the one thing that should refuse to be deleted. It costs three lines and has saved real outages.
Results
- Every network and cluster resource is managed in Terraform. Nothing is clicked into existence any more.
- All four clusters come up in a single automated pipeline run.
- A new environment is a new variable file, not new code.
- The shared network is protected from accidental destruction, and all service projects route egress through one NAT gateway.
The same pattern, as open source
The write-up above stays generic, so here is the same pattern as code you can actually read. I built a landing zone for each major cloud: a Terraform plus GitHub Actions setup for multi-environment Kubernetes, with the security defaults baked in (remote state, no secrets in the repo, least-privilege IAM, a prominent security notice in each README).
- GCP landing zone — GKE, Shared VPC, Terraform and GitHub Actions. The closest mirror of the architecture above.
- AWS landing zone — the same shape on EKS: VPC, IAM and multi-environment Terraform.
- Azure landing zone — AKS with a focus on governance, security and multi-environment deployments.
What I would tell someone starting this
- Put the network in a Shared VPC host project from day one. Retrofitting it onto clusters that already own their VPC is painful.
- Add
prevent_destroyto anything you cannot afford to recreate, before you need it, not after the first scare. - Make a new environment a variable file, not a copy-paste of the code. If adding an environment means editing resources, the config is not modular yet.
- Keep state remote and secrets out of the repo. The landing zones above show the defaults I use.