GCP Lesson 24 of 98

Building a Shared VPC: Centralized Networking Across Many GCP Projects

In a mature GCP organization, dozens of teams want their own projects but nobody wants dozens of disconnected networks. Shared VPC lets a single host project own the network while many service projects attach to it and deploy workloads into its subnets, keeping connectivity, IP space, and firewall policy under one roof. This walkthrough builds that seam end to end: model selection, project attachment, IP planning, subnet-scoped IAM, private access patterns, hybrid links, and centralized DNS.

In a nutshell

Level: Advanced · Time: ~26 min

Picture an office tower. The host project is the building’s landlord and facilities team: they own the plumbing, the electrical, the elevators, the security desk at the lobby, and the single fibre line that connects the whole building to the street. The service projects are the tenant companies that lease floors. Each tenant brings its own desks and staff — that’s your VMs, your GKE clusters, your Cloud Run services — but no tenant drills its own hole to the street or runs its own plumbing. They plug into what the building already provides.

That one picture explains almost every rule in this lesson. The building manager (the platform/network team) decides which tenant gets a keycard to which floor — that’s subnet-scoped IAM (compute.networkUser on one subnet, not the whole building). Everyone shares one security desk (firewall policy), one directory in the mailroom (Cloud DNS), one loading dock to the outside world (hybrid connectivity and Cloud NAT), and one street connection that the landlord maintains once for everybody. Tenants never negotiate their own street connection, and they never see each other’s keys.

Why a beginner should care: without this model, every team spins up its own network, its own VPN to the data centre, its own DNS, and its own overlapping 10.0.0.0/8. Within a year you have fifty islands that can’t talk, IP ranges that collide the moment you try to connect them, and no single place to enforce “no workload gets a public IP.” Shared VPC is how one organization keeps central network control while letting many teams move independently — it is the network backbone of a GCP landing zone.

The one sentence to carry through: the host project owns the network (VPC, subnets, IP plan, firewall, DNS, hybrid links); service projects own only their workloads and consume the host’s subnets through a narrow, subnet-scoped grant.

This is an advanced lesson. It assumes you already understand the global VPC model, subnets, and firewall rules from Google Cloud VPC, In Depth, and where networking sits inside a landing zone. If “CIDR”, “subnet”, or “firewall rule” is new, start there first. After this lesson you will be able to:

The whole model fits in one picture:

Shared VPC landing-zone architecture — a host project owns the VPC, subnets, IP plan, firewall policy, hybrid links and DNS, while service projects attach and deploy VMs and GKE into delegated subnets

Read it left to right. Governance at the org/folder level enables the host and enforces guardrails (only Shared VPC Admin can turn a host on; org policy denies external IPs). The host project owns the one global VPC, the regional subnets and IP plan, and the firewall policy. Delegation is the seam: compute.networkUser bound at an individual subnet lets exactly the right team — and its service agents — deploy there. Service projects then attach and run VMs and GKE that draw internal IPs from the host’s subnets. Finally every service project inherits the shared edge: private access to Google APIs, hybrid links to on-prem, and central DNS, all built once in the host. The six badges mark where the model is powerful — and where it silently breaks; we return to each below.

The core split: host project vs service projects

Before the commands, internalize the ownership line, because every permission error and every design argument in Shared VPC traces back to it. One team owns the network; other teams own their workloads; a narrow grant is the contract between them.

The host project owns Each service project owns
The VPC network (global, custom-mode) Its workloads: VMs, GKE clusters, Cloud SQL instances, Cloud Run services
Every subnet and the IP plan (primary + secondary ranges) Compute-level IAM for its own resources
Firewall rules and hierarchical firewall policies App configuration, images, data
Cloud Router + HA VPN / Interconnect (hybrid) The bill for its own compute and egress
Cloud NAT, Private Google Access, PSC endpoints Requests for new subnets/rules it doesn’t own
Cloud DNS private and forwarding zones

The thing in the middle — neither purely host nor purely service — is the grant: compute.networkUser at subnet scope, plus the service-agent IAM that lets managed services provision on a team’s behalf. Get that seam right and a new team onboards by attaching a project and receiving a keycard to one subnet. Get it wrong and you either over-grant (every team can use every subnet) or under-grant (GKE clusters refuse to create). The rest of this lesson is that seam, built carefully.

Step 0: Choose the right model

Before touching gcloud, decide why you are not just peering everything. The three common patterns solve different problems.

Model Connectivity IAM / ownership Best for
Shared VPC Service projects deploy into the host’s subnets; one routing domain Network team owns subnets and firewall; app teams own VMs A single org’s landing zone with central network control
VPC Peering Two independent VPCs exchange routes, non-transitive Each side owns its own network fully Connecting separately-owned VPCs (e.g. partner, acquisition)
Network Connectivity Center (NCC) Hub-and-spoke; spokes can be VPCs, HA VPN, Interconnect Each spoke independent; hub provides transitivity Many VPCs/sites needing transitive any-to-any reach

The decisive question is ownership. Shared VPC centralizes control: a platform team defines subnets and firewall rules, and application teams consume them without ever creating a network. Peering keeps networks fully separate and is non-transitive (A-B and B-C does not give you A-C), which collapses at scale. NCC adds a transitive hub and is the right tool when you have many already-independent VPCs or a large hybrid estate to stitch together. These compose: a common enterprise topology is a Shared VPC per environment, with those host VPCs as NCC spokes for cross-environment or cross-region transitivity.

Rule of thumb: one team should govern IP allocation and firewall policy for a blast radius. That governance boundary is your Shared VPC.

Step 1: Designate the host project and attach service projects

You need the Compute Shared VPC Admin role (roles/compute.xpnAdmin) at the organization or folder level to enable a host and attach services. Project-level Owner is not enough.

# Enable the project as a Shared VPC host
gcloud compute shared-vpc enable HOST_PROJECT_ID

# Attach a service project to the host
gcloud compute shared-vpc associated-projects add SERVICE_PROJECT_ID \
  --host-project HOST_PROJECT_ID

# Verify the association
gcloud compute shared-vpc list-associated-resources HOST_PROJECT_ID

A host project can serve many service projects; a service project attaches to exactly one host. Keep the host project lean: it should contain the VPC, subnets, firewall rules, Cloud Routers, VPN/Interconnect, and Cloud DNS, and ideally no application workloads.

In Terraform the same wiring is explicit and reviewable:

resource "google_compute_shared_vpc_host_project" "host" {
  project = var.host_project_id
}

resource "google_compute_shared_vpc_service_project" "svc" {
  host_project    = google_compute_shared_vpc_host_project.host.project
  service_project = var.service_project_id
}

Step 2: Plan IP space and regional layout

IP planning is the decision you cannot cheaply undo. Subnets are regional in GCP, and a VPC is global, so a single VPC spans every region without peering. Carve a clear hierarchy out of RFC 1918 space and leave room to grow.

A workable convention is to give each region a large aggregate and slice subnets from it by environment and tier:

10.0.0.0/8                  org aggregate (reserve generously)
  10.10.0.0/16              region: us-central1
    10.10.0.0/20            prod   - general workloads
    10.10.16.0/20           prod   - GKE nodes
    10.10.64.0/20           nonprod
  10.20.0.0/16              region: europe-west1

For GKE you also need secondary ranges on the subnet for Pods and Services. Size the Pod range deliberately: with the default of 110 Pods per node, plan roughly a /24 of Pod IPs per node, which makes Pod ranges the fastest way to exhaust RFC 1918.

gcloud compute networks create hub-vpc \
  --project=HOST_PROJECT_ID \
  --subnet-mode=custom

gcloud compute networks subnets create prod-usc1 \
  --project=HOST_PROJECT_ID \
  --network=hub-vpc \
  --region=us-central1 \
  --range=10.10.0.0/20 \
  --secondary-range=pods=10.110.0.0/16,services=10.120.0.0/20 \
  --enable-private-ip-google-access \
  --enable-flow-logs

Avoiding RFC 1918 exhaustion is mostly discipline: never assign overlapping ranges (peering, VPN, and Interconnect all break on overlap), keep a documented IPAM source of truth, and reserve a separate non-overlapping block for GKE Pods so it never collides with on-prem.

Step 3: Delegate subnet-level access with the right scope

This is the part teams get wrong. Granting roles/compute.networkUser at the host project level lets a service project use every subnet and shared resource. For least privilege, bind compute.networkUser at the individual subnet level so a team can only deploy into the subnets they own.

# Per-subnet grant: this team can only use prod-usc1
gcloud compute networks subnets add-iam-policy-binding prod-usc1 \
  --project=HOST_PROJECT_ID \
  --region=us-central1 \
  --member="group:team-payments@example.com" \
  --role="roles/compute.networkUser"

You typically grant compute.networkUser to two principals: the human/group deploying resources, and the service agents that provision on their behalf. GKE and some managed services act through Google-managed service accounts (for example the GKE service agent and the Google APIs service agent), and those agents need networkUser on the subnet and its secondary ranges, plus roles/container.hostServiceAgentUser on the host project for GKE.

# GKE in a service project needs its host service agent user role
gcloud projects add-iam-policy-binding HOST_PROJECT_ID \
  --member="serviceAccount:service-SVC_PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com" \
  --role="roles/container.hostServiceAgentUser"

Keep the scope tight from day one. Walking back an org-wide networkUser binding after fifty teams depend on it is a multi-quarter project.

Step 4: Private access patterns

Workloads in the host subnets usually should not have external IPs. Wire up private egress to Google and producer services in the host project so every service project inherits it.

Private Google Access lets instances without external IPs reach Google APIs and services over internal IPs. Enable it per subnet (the --enable-private-ip-google-access flag above) and ensure DNS resolves *.googleapis.com appropriately (the private.googleapis.com199.36.153.8/30 — or restricted.googleapis.com199.36.153.4/30 — virtual IP ranges combined with a route).

Private Service Connect (PSC) gives you a private endpoint inside your VPC for Google APIs or for a third party’s published service, keeping traffic off the internet. The endpoint for the Google APIs bundle is a global internal address and forwarding rule; create it in the host project so it is reachable from all service projects:

# Reserve a GLOBAL internal address for the PSC endpoint
# (a reserved endpoint IP that must not overlap any subnet range)
gcloud compute addresses create psc-googleapis \
  --project=HOST_PROJECT_ID \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=10.10.200.10 \
  --network=hub-vpc

# Global forwarding rule targeting the Google APIs bundle
gcloud compute forwarding-rules create psc-googleapis-fr \
  --project=HOST_PROJECT_ID \
  --global \
  --network=hub-vpc \
  --address=psc-googleapis \
  --target-google-apis-bundle=all-apis

Serverless VPC Access connectors let Cloud Run, Cloud Functions, and App Engine reach internal resources in the Shared VPC. Create the connector in the host project against a dedicated /28 and grant the service project’s serverless agents networkUser:

gcloud compute networks vpc-access connectors create serverless-usc1 \
  --project=HOST_PROJECT_ID \
  --region=us-central1 \
  --network=hub-vpc \
  --range=10.8.0.0/28

Newer Cloud Run revisions support Direct VPC egress, which skips the connector entirely and scales better. Prefer it for new Cloud Run services; keep connectors for Cloud Functions and App Engine standard.

Step 5: Hybrid connectivity into the host project

Terminate all on-prem connectivity in the host project so every service project reaches the data center through one governed path. Use Cloud Interconnect (Dedicated or Partner) for high, predictable bandwidth, and HA VPN for encrypted connectivity over the internet. Both attach to a Cloud Router that exchanges routes via BGP, and those learned routes are visible to all service projects automatically.

HA VPN gives you a 99.99% SLA when you build two interfaces to two peer devices:

gcloud compute routers create hub-router \
  --project=HOST_PROJECT_ID \
  --network=hub-vpc \
  --region=us-central1 \
  --asn=64512

gcloud compute vpn-gateways create hub-ha-vpn-gw \
  --project=HOST_PROJECT_ID \
  --network=hub-vpc \
  --region=us-central1

From there you create two vpn-tunnels (one per gateway interface), peer BGP sessions on hub-router, and advertise your VPC ranges. Because routing lives in the host project, a new service project gets on-prem reachability the moment it attaches and is granted a subnet, with no per-project VPN to manage. The mechanics of Cloud Router, BGP sessions, and route advertisement are covered in depth in HA VPN, Cloud Router & BGP.

Watch route quotas. Dynamic routes learned over BGP and custom static routes both count against per-VPC limits. Aggregate advertised prefixes from on-prem rather than leaking hundreds of specifics.

Step 6: Centralized DNS

Run Cloud DNS in the host project. Private zones authoritative for your internal domains attach to the host VPC, so every service project resolves them. For resolving on-prem names, use DNS forwarding zones (forward to your on-prem resolvers); for the reverse, configure inbound server policy so on-prem can resolve GCP names.

# Private zone for internal names, attached to the host VPC
gcloud dns managed-zones create internal-corp \
  --project=HOST_PROJECT_ID \
  --dns-name="corp.example.internal." \
  --description="Internal records" \
  --visibility=private \
  --networks=hub-vpc

DNS peering lets one VPC delegate resolution of a zone to another VPC’s DNS configuration. In a Shared VPC this is mostly unnecessary because service projects already resolve the host VPC’s private zones, but it is the mechanism when you bridge resolution between separate VPCs (for example a Shared VPC host and a peered partner VPC).

Verify

Confirm the seam actually works before handing it to teams.

# Host is enabled and the right service projects are attached
gcloud compute shared-vpc list-associated-resources HOST_PROJECT_ID

# Subnet-level IAM shows only the intended bindings
gcloud compute networks subnets get-iam-policy prod-usc1 \
  --project=HOST_PROJECT_ID --region=us-central1

# A test VM in a SERVICE project can target the host subnet
gcloud compute instances create conn-test \
  --project=SERVICE_PROJECT_ID \
  --zone=us-central1-a \
  --subnet=projects/HOST_PROJECT_ID/regions/us-central1/subnetworks/prod-usc1 \
  --no-address

# BGP sessions to on-prem are established and learning routes
gcloud compute routers get-status hub-router \
  --project=HOST_PROJECT_ID --region=us-central1

From the test VM, validate Private Google Access (curl -s https://storage.googleapis.com should succeed with no external IP), resolve an internal name from the central zone, and ping an on-prem host to prove hybrid routing. Then delete the test VM.

Enterprise scenario

A fintech platform team ran one Shared VPC per environment and had wired compute.networkUser at subnet scope cleanly. Then a new service project’s GKE Autopilot clusters refused to create, failing with Google Compute Engine: Required 'compute.subnetworks.use' permission on the shared subnet. The human operator had networkUser on the subnet, so the assumption was the binding was correct.

The gotcha: Autopilot and node auto-provisioning provision through the GKE host service agent, not the operator’s identity. That agent (service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com) needs networkUser on the subnet and both secondary ranges (Pods and Services), plus container.hostServiceAgentUser on the host project. They had granted it on the primary range only, so cluster creation passed subnet checks but died allocating the Pod range.

The fix was to bind the agent at the secondary-range level explicitly, which the subnet IAM binding does not cover by default:

gcloud compute networks subnets add-iam-policy-binding prod-usc1 \
  --project=HOST_PROJECT_ID --region=us-central1 \
  --member="serviceAccount:service-SVC_PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com" \
  --role="roles/compute.networkUser"

They then codified the full set (agent + secondary ranges + hostServiceAgentUser) into the Terraform module that stamps every service project, so the next forty teams onboarded without a ticket. The lesson: in Shared VPC, service-agent IAM is the invisible half of the contract, and secondary ranges are where it silently breaks.

Going deeper

The steps above stand up a working Shared VPC. This section is for the reader who has to operate one at scale — where the IAM edge cases, IP math, quotas, and guardrails decide whether the landing zone stays sane past fifty projects.

The IAM you actually need

Shared VPC IAM is a small set of roles, but the mistakes come from missing one of them or binding it at the wrong scope. Grant the least role at the lowest node, and remember that managed services provision through Google-managed robots, not the human operator.

Role Granted to At Why
roles/compute.xpnAdmin Platform/network admins Org or folder Enable a host, attach/detach service projects. Project Owner cannot do this.
roles/compute.networkUser Deploying group + service agents Subnet (not host project) Use one subnet + its secondary ranges. Subnet scope = least privilege.
roles/container.hostServiceAgentUser Service project’s GKE agent (service-NUM@container-engine-robot…) Host project Lets the service project’s GKE agent act as the host’s GKE agent to manage networking.
roles/compute.networkViewer Auditors, dashboards Host project Read-only visibility into the network without deploy rights.

For GKE specifically, two service agents need networkUser on the subnet, not one: the GKE agent service-SVC_NUM@container-engine-robot.iam.gserviceaccount.com and the Google APIs (cloud services) agent SVC_NUM@cloudservices.gserviceaccount.com. The enterprise scenario above shows what happens when the set is incomplete — clusters pass the primary-range check and die on the Pod range. For serverless, the connector needs the service project’s serverless agents to hold roles/vpcaccess.user on the connector plus networkUser on its subnet.

A subnet-level networkUser binding covers the subnet’s secondary ranges, so you normally bind once at the subnet. If you need finer control — a team that may use the primary range but only one named secondary range — you scope the grant to specific ranges (an option the Console’s “add subnet permissions” flow exposes, and which you can express with IAM conditions).

IP planning that survives scale

The Pod secondary range is almost always the first thing to run out, because GKE does not hand each node a tidy 110 addresses — it allocates each node a CIDR sized to 2 × maxPodsPerNode rounded up to the next power of two. At the default 110 Pods per node that is 220 → /24 (256 addresses) per node.

Consumer Rough sizing Note
Subnet primary (VM/node NICs) /20 ≈ 4,096 IPs (minus 4 reserved) One primary IP per VM NIC and per GKE node.
GKE Pod secondary /24 per node → size for peak nodes A /16 Pod range caps you near ~256 nodes; a 1,000-node cluster needs a /14.
GKE Services secondary /20 per cluster is generous ClusterIP space; rarely the bottleneck.
PSA (managed services) A dedicated /16/20 you allocate once Cloud SQL, Memorystore, etc. draw from a Private Service Access range you reserve on the VPC.
PSC / serverless / proxy-only /28/24 reserved blocks PSC endpoints, serverless connectors, and regional L7 LBs each need their own small ranges.

When RFC 1918 genuinely runs dry, GCP supports privately-used public IP addresses (routing a public range you own, or one you don’t advertise, internally) and non-RFC-1918 ranges for subnets — a pressure valve, not a first choice. The durable answer is discipline: an authoritative IPAM, non-overlapping allocations per region and environment, and a Pod range that can never collide with on-prem.

Which private-access pattern, when

“Private access” is four different mechanisms that solve overlapping problems. Choosing wrong means either a public IP you didn’t want or a connector you didn’t need.

Pattern Reaches Use when
Private Google Access Google APIs (*.googleapis.com, gcr.io) VMs/GKE with no external IP need Google APIs. Free, per-subnet flag.
Private Service Access (PSA) Google-managed producer services (Cloud SQL, Memorystore) You need a private IP to a managed service; requires a reserved range + VPC peering to the producer.
Private Service Connect (PSC) Google APIs bundle, or a third-party/published service You want a private endpoint IP you control, VPC-SC compatibility, or to consume a partner’s service.
Serverless VPC connector / Direct VPC egress Internal resources from Cloud Run/Functions/App Engine Serverless code must reach VMs/DBs on internal IPs. Prefer Direct VPC egress for new Cloud Run.

Build all of these in the host project so every attached service project inherits them. Duplicating a PSC endpoint or connector per service project is the anti-pattern the whole model exists to avoid.

Guardrails: org policy, hierarchical firewall, VPC Service Controls

Central network control is only real if it is enforced, not documented. Layer three mechanisms:

Quotas, limits, and blast radius

A single Shared VPC has hard edges. Service projects attachable to one host, subnets per network, and — critically — dynamic + static routes per VPC all have quotas, and a hybrid estate that leaks hundreds of on-prem specifics will hit the route ceiling and stop learning new prefixes. Aggregate advertised prefixes at the Cloud Router. The deeper reason to run one Shared VPC per environment rather than one giant host for everything is blast radius: a bad firewall change, a route-quota exhaustion, or a mis-peer is contained to prod or nonprod, never both. Per-environment hosts, stitched with NCC only where you need transitivity, is the pattern that scales.

Cost model and day-2

Shared VPC itself is free — you pay for what flows through it. Each service project is billed for its own VMs and their egress; inter-region egress across the global VPC is real money and easy to forget when a subnet in us-central1 chats with one in europe-west1. Cloud NAT, Interconnect/VPN, and VPC Flow Logs are billed in the host project, so the platform team owns those line items — plan the flow-log sampling rate accordingly. On day two, migrating an existing standalone project into Shared VPC means recreating its resources on host subnets (you cannot move a running VM’s NIC between networks), so migrate service-by-service behind the same DNS names. Codify the whole onboarding — attach, subnet grant, both GKE agents, hostServiceAgentUser, DNS — into a Terraform module so the fiftieth project is a one-line change, not a ticket.

Common beginner mistakes

These are misconceptions — the wrong mental model that produces a whole class of errors — not one-off symptoms. Each pairs the belief with the correction.

Practice challenges

Work these top to bottom; they escalate from picking the model to locking the estate down. Each solution is one click away — try first, then check. No live GCP is assumed; the commands are schema-correct and real.

Challenge 1 (Beginner) — Pick the model. For each case choose Shared VPC, VPC Peering, or NCC and say why: (a) one company’s landing zone where a platform team must own all subnets and firewall policy; (b) connecting to an acquired company’s existing, independently-owned VPC; © 30 already-independent VPCs across three regions that need transitive any-to-any reach.

<details> <summary>Solution</summary>

(a) Shared VPC — central ownership of one network with many consuming projects is exactly its purpose. (b) VPC Peering — two separately-owned networks join without either giving up control; you accept its non-transitivity for a single link. © NCC — a hub provides the transitivity peering lacks, with VPCs and hybrid links as spokes. Why: the deciding axis is ownership and transitivity — one owner → Shared VPC, two owners → peering, many owners needing any-to-any → NCC. </details>

Challenge 2 (Beginner) — Stand up the host. Write the commands to enable HOST_PROJECT_ID as a host, attach SERVICE_PROJECT_ID, and verify the association. Which role at which level do you need?

<details> <summary>Solution</summary>

gcloud compute shared-vpc enable HOST_PROJECT_ID
gcloud compute shared-vpc associated-projects add SERVICE_PROJECT_ID \
  --host-project HOST_PROJECT_ID
gcloud compute shared-vpc list-associated-resources HOST_PROJECT_ID

You need roles/compute.xpnAdmin (Compute Shared VPC Admin) at the organization or folder level. Why: enabling a host is an org-hierarchy operation; project-level Owner cannot do it. </details>

Challenge 3 (Intermediate) — Least-privilege delegation. The team-payments group must deploy into prod-usc1 (region us-central1) and no other subnet. Write the binding, and say why granting networkUser at the host-project level would be wrong here.

<details> <summary>Solution</summary>

gcloud compute networks subnets add-iam-policy-binding prod-usc1 \
  --project=HOST_PROJECT_ID --region=us-central1 \
  --member="group:team-payments@example.com" \
  --role="roles/compute.networkUser"

Why: binding at the subnet scopes the team to exactly that subnet and its secondary ranges. A host-project-level grant would let them deploy into every subnet and shared resource — over-privileged, and painful to walk back once other teams rely on the network. </details>

Challenge 4 (Intermediate) — GKE won’t create. In a service project, team-payments (who do have networkUser on prod-usc1) create a GKE Autopilot cluster and it fails with Required 'compute.subnetworks.use' permission. Which identities are missing which roles, and where?

<details> <summary>Solution</summary>

The service agents, not the humans, provision the cluster. Grant on the host: roles/container.hostServiceAgentUser to service-SVC_NUM@container-engine-robot.iam.gserviceaccount.com. Grant roles/compute.networkUser on the subnet prod-usc1 (covering its Pod/Service secondary ranges) to both service-SVC_NUM@container-engine-robot.iam.gserviceaccount.com and SVC_NUM@cloudservices.gserviceaccount.com. Why: GKE acts through Google-managed robots; a human’s subnet grant never covers them, and the Pod range is where it silently breaks. </details>

Challenge 5 (Advanced) — Size the ranges. A subnet must host up to 200 GKE nodes at 110 Pods/node, plus up to 4,000 Services. Size the subnet primary range, the Pod secondary range, and the Services secondary range, showing the Pod math.

<details> <summary>Solution</summary>

Why: the Pod range dominates because allocation is per-node /24, so it must be sized against peak node count, not Pod count directly. </details>

Challenge 6 (Advanced) — Lock the estate. Enforce three things org-wide: no workload may get an external IP; only approved projects may be Shared VPC hosts; and the on-prem route count must stay under the per-VPC quota. Name the mechanisms.

<details> <summary>Solution</summary>

Why: guardrails must be enforced by org policy and route design, not left to documentation — central control is only real when a team cannot opt out of it. </details>

Checklist

Pitfalls and next steps

The recurring failure mode is owning the seam: the network team owns subnets and firewall rules in the host project, while application teams deploy workloads from service projects. Make that contract explicit, because a developer who cannot open a firewall rule will file a ticket, not a gcloud command. Prefer hierarchical firewall policies at the folder/org level for guardrails, and delegate scoped rule creation only where a team genuinely needs it.

Other traps: overlapping CIDRs that silently break peering and VPN; org-wide networkUser grants that erase least privilege; forgetting service-agent IAM so GKE clusters fail to create with cryptic permission errors; and route-quota exhaustion from leaking on-prem specifics. Next, codify all of this in Terraform with a per-environment host project, layer NCC if you need transitive multi-region or multi-VPC reach, and add Network Firewall Policies plus org policies (compute.vmExternalIpAccess) so the landing zone stays secure as it scales.

Glossary

GCPShared VPCNetworkingVPCIAM
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments