Network segmentation is a critical defense-in-depth strategy that limits an attacker's ability to move laterally after initial compromise. A flat network allows attackers to pivot from a compromised web server to databases containing sensitive data. Proper segmentation creates security boundaries that contain breaches.
This guide covers VPC architecture, firewall configuration, and advanced controls like VPC Service Controls. This expands on Tip 11 from our 30 Cloud Security Tips for 2026 guide on implementing network segmentation.
VPC Architecture Overview
A well-designed GCP network architecture includes:
- Separate VPCs - Production vs. non-production environments
- Tiered subnets - Web, application, and database tiers
- Firewall rules - Explicit allow rules between tiers
- VPC Service Controls - Data exfiltration prevention
- Private Google Access - Access Google APIs without public IPs
Step 1: Create VPC Networks
Create separate VPCs for environment isolation:
Via Google Cloud Console
-
- Navigate to [VPC Network](https://console.cloud.google.com/networking/networks)
- Click **Create VPC Network**
- Configure:
-
Name:
prod-vpc -
Subnet creation mode: Custom
-
MTU: 1460 (default) or 1500 for jumbo frames
-
Add subnets for each tier (see Step 2)
-
Click Create
Via gcloud CLI
# Create production VPC
gcloud compute networks create prod-vpc \
--subnet-mode=custom \
--bgp-routing-mode=regional \
--project=PROJECT_ID
# Create staging VPC
gcloud compute networks create staging-vpc \
--subnet-mode=custom \
--bgp-routing-mode=regional \
--project=PROJECT_ID
# Create development VPC
gcloud compute networks create dev-vpc \
--subnet-mode=custom \
--bgp-routing-mode=regional \
--project=PROJECT_IDVia Terraform
resource "google_compute_network" "prod_vpc" {
name = "prod-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
project = var.project_id
}
resource "google_compute_network" "staging_vpc" {
name = "staging-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
project = var.project_id
}
resource "google_compute_network" "dev_vpc" {
name = "dev-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
project = var.project_id
}Step 2: Create Subnets for Network Tiers
Create subnets to segment by application tier:
Via gcloud CLI
# Web tier subnet (public-facing load balancers)
gcloud compute networks subnets create prod-web-subnet \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.1.0/24 \
--enable-private-ip-google-access \
--project=PROJECT_ID
# Application tier subnet
gcloud compute networks subnets create prod-app-subnet \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.2.0/24 \
--enable-private-ip-google-access \
--project=PROJECT_ID
# Database tier subnet
gcloud compute networks subnets create prod-db-subnet \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.3.0/24 \
--enable-private-ip-google-access \
--project=PROJECT_ID
# Management/bastion subnet
gcloud compute networks subnets create prod-mgmt-subnet \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.10.0/24 \
--enable-private-ip-google-access \
--project=PROJECT_IDVia Terraform
resource "google_compute_subnetwork" "prod_web" {
name = "prod-web-subnet"
ip_cidr_range = "10.0.1.0/24"
region = "us-central1"
network = google_compute_network.prod_vpc.id
private_ip_google_access = true
log_config {
aggregation_interval = "INTERVAL_5_SEC"
flow_sampling = 0.5
metadata = "INCLUDE_ALL_METADATA"
}
}
resource "google_compute_subnetwork" "prod_app" {
name = "prod-app-subnet"
ip_cidr_range = "10.0.2.0/24"
region = "us-central1"
network = google_compute_network.prod_vpc.id
private_ip_google_access = true
log_config {
aggregation_interval = "INTERVAL_5_SEC"
flow_sampling = 0.5
metadata = "INCLUDE_ALL_METADATA"
}
}
resource "google_compute_subnetwork" "prod_db" {
name = "prod-db-subnet"
ip_cidr_range = "10.0.3.0/24"
region = "us-central1"
network = google_compute_network.prod_vpc.id
private_ip_google_access = true
log_config {
aggregation_interval = "INTERVAL_5_SEC"
flow_sampling = 0.5
metadata = "INCLUDE_ALL_METADATA"
}
}Step 3: Configure Firewall Rules
Create explicit allow rules between tiers:
Delete Default Rules
Remove overly permissive default rules:
# List default rules
gcloud compute firewall-rules list --filter="network=prod-vpc" --project=PROJECT_ID
# Delete default-allow-internal if it exists
gcloud compute firewall-rules delete default-allow-internal --project=PROJECT_IDCreate Tier-Based Rules
# Allow HTTPS from anywhere to web tier (through load balancer)
gcloud compute firewall-rules create prod-allow-lb-to-web \
--network=prod-vpc \
--direction=INGRESS \
--priority=1000 \
--action=ALLOW \
--rules=tcp:80,tcp:443 \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=web-tier \
--project=PROJECT_ID
# Allow web tier to app tier
gcloud compute firewall-rules create prod-allow-web-to-app \
--network=prod-vpc \
--direction=INGRESS \
--priority=1000 \
--action=ALLOW \
--rules=tcp:8080 \
--source-tags=web-tier \
--target-tags=app-tier \
--project=PROJECT_ID
# Allow app tier to database tier
gcloud compute firewall-rules create prod-allow-app-to-db \
--network=prod-vpc \
--direction=INGRESS \
--priority=1000 \
--action=ALLOW \
--rules=tcp:5432,tcp:3306 \
--source-tags=app-tier \
--target-tags=db-tier \
--project=PROJECT_ID
# Allow SSH from bastion only
gcloud compute firewall-rules create prod-allow-bastion-ssh \
--network=prod-vpc \
--direction=INGRESS \
--priority=1000 \
--action=ALLOW \
--rules=tcp:22 \
--source-tags=bastion \
--target-tags=web-tier,app-tier,db-tier \
--project=PROJECT_ID
# Deny all other internal traffic (explicit deny for logging)
gcloud compute firewall-rules create prod-deny-internal-all \
--network=prod-vpc \
--direction=INGRESS \
--priority=65534 \
--action=DENY \
--rules=all \
--source-ranges=10.0.0.0/8 \
--enable-logging \
--project=PROJECT_IDTerraform Firewall Rules
resource "google_compute_firewall" "allow_lb_to_web" {
name = "prod-allow-lb-to-web"
network = google_compute_network.prod_vpc.name
allow {
protocol = "tcp"
ports = ["80", "443"]
}
source_ranges = ["130.211.0.0/22", "35.191.0.0/16"]
target_tags = ["web-tier"]
priority = 1000
}
resource "google_compute_firewall" "allow_web_to_app" {
name = "prod-allow-web-to-app"
network = google_compute_network.prod_vpc.name
allow {
protocol = "tcp"
ports = ["8080"]
}
source_tags = ["web-tier"]
target_tags = ["app-tier"]
priority = 1000
}
resource "google_compute_firewall" "allow_app_to_db" {
name = "prod-allow-app-to-db"
network = google_compute_network.prod_vpc.name
allow {
protocol = "tcp"
ports = ["5432", "3306"]
}
source_tags = ["app-tier"]
target_tags = ["db-tier"]
priority = 1000
}
resource "google_compute_firewall" "deny_all_internal" {
name = "prod-deny-internal-all"
network = google_compute_network.prod_vpc.name
deny {
protocol = "all"
}
source_ranges = ["10.0.0.0/8"]
priority = 65534
log_config {
metadata = "INCLUDE_ALL_METADATA"
}
}Step 4: Implement Shared VPC (Enterprise)
For large organizations, use Shared VPC to centralize network management:
Enable Shared VPC
# Enable host project
gcloud compute shared-vpc enable HOST_PROJECT_ID
# Attach service project
gcloud compute shared-vpc associated-projects add SERVICE_PROJECT_ID \
--host-project=HOST_PROJECT_IDGrant Subnet Access
# Grant service project access to specific subnet
gcloud compute networks subnets add-iam-policy-binding prod-app-subnet \
--region=us-central1 \
--member="serviceAccount:[email protected]" \
--role="roles/compute.networkUser" \
--project=HOST_PROJECT_IDTerraform Shared VPC
resource "google_compute_shared_vpc_host_project" "host" {
project = var.host_project_id
}
resource "google_compute_shared_vpc_service_project" "service" {
host_project = google_compute_shared_vpc_host_project.host.project
service_project = var.service_project_id
}
resource "google_compute_subnetwork_iam_member" "network_user" {
project = var.host_project_id
region = "us-central1"
subnetwork = google_compute_subnetwork.prod_app.name
role = "roles/compute.networkUser"
member = "serviceAccount:${var.service_project_number}@cloudservices.gserviceaccount.com"
}Step 5: Configure VPC Service Controls
Create security perimeters to prevent data exfiltration:
Create Access Policy
# Create access policy (organization level)
gcloud access-context-manager policies create \
--organization=ORGANIZATION_ID \
--title="Production Security Policy"Create Service Perimeter
# Create a perimeter protecting Cloud Storage and BigQuery
gcloud access-context-manager perimeters create prod-perimeter \
--title="Production Perimeter" \
--resources="projects/PROJECT_NUMBER" \
--restricted-services="storage.googleapis.com,bigquery.googleapis.com" \
--policy=POLICY_NUMBERCreate Access Level for Trusted Networks
# Create access level for corporate IP ranges
gcloud access-context-manager levels create trusted-network \
--title="Trusted Network" \
--basic-level-spec="ipSubnetworks=203.0.113.0/24,198.51.100.0/24" \
--combine-function=AND \
--policy=POLICY_NUMBER
# Update perimeter to allow access level
gcloud access-context-manager perimeters update prod-perimeter \
--add-access-levels=trusted-network \
--policy=POLICY_NUMBERTerraform VPC Service Controls
resource "google_access_context_manager_access_policy" "policy" {
parent = "organizations/${var.organization_id}"
title = "Production Security Policy"
}
resource "google_access_context_manager_access_level" "trusted_network" {
parent = "accessPolicies/${google_access_context_manager_access_policy.policy.name}"
name = "accessPolicies/${google_access_context_manager_access_policy.policy.name}/accessLevels/trusted_network"
title = "Trusted Network"
basic {
conditions {
ip_subnetworks = ["203.0.113.0/24", "198.51.100.0/24"]
}
}
}
resource "google_access_context_manager_service_perimeter" "prod_perimeter" {
parent = "accessPolicies/${google_access_context_manager_access_policy.policy.name}"
name = "accessPolicies/${google_access_context_manager_access_policy.policy.name}/servicePerimeters/prod_perimeter"
title = "Production Perimeter"
status {
resources = ["projects/${var.project_number}"]
restricted_services = [
"storage.googleapis.com",
"bigquery.googleapis.com"
]
access_levels = [
google_access_context_manager_access_level.trusted_network.name
]
}
}Step 6: Enable VPC Flow Logs
Monitor network traffic for security analysis:
# Enable flow logs on existing subnet
gcloud compute networks subnets update prod-app-subnet \
--region=us-central1 \
--enable-flow-logs \
--logging-aggregation-interval=interval-5-sec \
--logging-flow-sampling=0.5 \
--logging-metadata=include-all \
--project=PROJECT_IDBest Practices Summary
- Separate VPCs per environment - Production, staging, development isolation
- Use subnet tiers - Web, app, database with explicit firewall rules
- Default deny - Only allow explicitly required traffic
- Use network tags or service accounts - More flexible than IP-based rules
- Enable VPC Flow Logs - For traffic analysis and forensics
- Implement VPC Service Controls - Prevent data exfiltration
- Use Private Google Access - Access APIs without public IPs
- Deploy Cloud NAT - Outbound internet without public IPs
Related Resources
- 30 Cloud Security Tips for 2026 - Comprehensive cloud security guide
- GCP Cloud Armor Setup Guide - WAF and DDoS protection
- Secure Cloud SQL Access - Database network security
- VPC Network Documentation
- VPC Service Controls Documentation
Need help designing a secure network architecture for your Google Cloud environment? Contact InventiveHQ for expert guidance on VPC design and security controls.