Multi-Project Networking: Shared VPC
Scenario
In enterprise environments, networking resources (VPCs, VPNs, Interconnects) are centralized in a single "Host Project" managed by the Network Administrators. Developers build applications in isolated "Service Projects". Shared VPC allows you to share subnetworks from the Host Project into the Service Projects. You need to enable a Host Project, attach a Service Project, and deploy a VM in the Service Project using the Host's subnet.
- You will need two project IDs for variables: host_project_id and service_project_id.
- Enable Shared VPC using google_compute_shared_vpc_host_project.
- Attach the service project using google_compute_shared_vpc_service_project.
- Create a Subnet in the Host Project.
- Grant the Service Project's default Compute Service Account the roles/compute.networkUser role on the Host Project subnet.
- Deploy a Compute Engine instance in the Service Project that seamlessly uses the Host Project's subnet.
Additional Context
Subnet-Level vs Project-Level Sharing: You can either grant `networkUser` on the entire Host Project (giving developers access to all subnets globally), or strictly at the subnet level (giving the `web-dev` team access only to the `us-central1-web` subnet). Subnet-level sharing is the recommended security posture.
Billing: In Shared VPC, the Service Project pays for the Compute Engine VMs and egress data transfer, even though the network infrastructure lives in the Host Project.
variables.tf
variable "host_project_id" { type = string }
variable "service_project_id" { type = string }
variable "gcp_region" { type = string; default = "us-central1" }main.tf
provider "google" {
# No default project block here, passing project variables explicitly
}
# 1. Enable the Host Project
resource "google_compute_shared_vpc_host_project" "host" {
project = var.host_project_id
}
# 2. Attach the Service Project to the Host
resource "google_compute_shared_vpc_service_project" "service1" {
host_project = google_compute_shared_vpc_host_project.host.project
service_project = var.service_project_id
}
# 3. Create a Network + Subnet in the HOST project
resource "google_compute_network" "shared_vpc" {
name = "shared-network"
project = google_compute_shared_vpc_host_project.host.project
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "shared_subnet" {
name = "app-subnet-usea1"
project = google_compute_shared_vpc_host_project.host.project
region = var.gcp_region
network = google_compute_network.shared_vpc.id
cidr_range = "10.100.0.0/24"
}
# 4. Fetch the Service Project's default Compute Service Account
data "google_project" "service" {
project_id = var.service_project_id
}
# 5. Grant Subnet-level NetworkUser IAM role to the Service Project SA
# This allows VMs in the service project to connect to this specific subnet
resource "google_compute_subnetwork_iam_member" "network_user" {
project = google_compute_shared_vpc_host_project.host.project
region = google_compute_subnetwork.shared_subnet.region
subnetwork = google_compute_subnetwork.shared_subnet.name
# The required role for Shared VPC usage
role = "roles/compute.networkUser"
# Using the default Compute Engine SA string formatting
member = "serviceAccount:${data.google_project.service.number}[email protected]"
}
# 6. Deploy the VM in the SERVICE project, but attach it to the HOST subnet
resource "google_compute_instance" "app_vm" {
name = "shared-vpc-worker"
project = var.service_project_id
zone = "${var.gcp_region}-a"
machine_type = "e2-micro"
depends_on = [
google_compute_shared_vpc_service_project.service1,
google_compute_subnetwork_iam_member.network_user
]
boot_disk {
initialize_params { image = "debian-cloud/debian-11" }
}
network_interface {
# Notice how we must specify the fully qualified self_link for cross-project
subnetwork = google_compute_subnetwork.shared_subnet.self_link
}
}Workflow Commands
terraform init
# IMPORTANT: Ensure the APIs are enabled in both projects first!
# gcloud services enable compute.googleapis.com --project=my-host-project
# gcloud services enable compute.googleapis.com --project=my-service-project
terraform apply \
-var="host_project_id=my-host-project-111" \
-var="service_project_id=my-service-project-222"
terraform destroy \
-var="host_project_id=my-host-project-111" \
-var="service_project_id=my-service-project-222"
