Skip to main content

Network Security

TSC mapping: CC6.6 (Logical access restrictions from outside system boundaries), CC6.7 (Data transmission controls)

Network controls are a heavily-evidenced area for SOC 2. Auditors will review VPC designs, firewall rules, WAF configurations, and TLS policies. The core principle: deny by default, allow by exception.


1. VPC Design — Defence in Depth​

Block default VPC creation at the organization level​

# Enforce Organization Policy: prevent default network creation in new projects
gcloud resource-manager org-policies set-policy \
--organization=<org-id> \
- <<'EOF'
name: organizations/<org-id>/policies/compute.skipDefaultNetworkCreation
spec:
rules:
- enforce: true
EOF

Create a custom VPC with private subnets​

# Create a custom-mode VPC (no auto-created subnets)
gcloud compute networks create prod-vpc \
--project=<project-id> \
--subnet-mode=custom \
--bgp-routing-mode=regional \
--mtu=1460

# Create private subnets with VPC Flow Logs enabled
gcloud compute networks subnets create snet-app \
--project=<project-id> \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.2.0/24 \
--enable-private-ip-google-access \
--enable-flow-logs \
--logging-aggregation-interval=interval-5-sec \
--logging-flow-sampling=1.0

gcloud compute networks subnets create snet-data \
--project=<project-id> \
--network=prod-vpc \
--region=us-central1 \
--range=10.0.3.0/24 \
--enable-private-ip-google-access \
--enable-flow-logs

Recommended subnet layout:

VPC: prod-vpc (custom mode)
├── snet-lb (10.0.1.0/24) ← External load balancer only
├── snet-app (10.0.2.0/24) ← Application layer — no external IPs
├── snet-data (10.0.3.0/24) ← Cloud SQL, Memorystore (Private Service Access)
└── snet-proxy (10.0.4.0/24) ← Managed proxy subnet for Internal Load Balancer

Enforce no external IPs on VMs via Organization Policy:

gcloud resource-manager org-policies set-policy \
--project=<project-id> \
- <<'EOF'
name: projects/<project-id>/policies/compute.vmExternalIpAccess
spec:
rules:
- denyAll: true
EOF

Reference: VPC networks → · Organization policy constraints →


2. VPC Firewall Rules — Least Privilege​

GCP firewall rules are stateful and applied at the network level. SOC 2 auditors specifically look for rules allowing 0.0.0.0/0 inbound on admin ports (22, 3389).

Audit for unrestricted admin access​

# Find firewall rules allowing SSH (22) or RDP (3389) from the internet
gcloud compute firewall-rules list \
--project=<project-id> \
--filter="direction=INGRESS AND disabled=false" \
--format="table(name,network,sourceRanges,allowed[].ports.flatten())" | \
grep -E "(:22|:3389|all)"

# Delete an overly permissive rule
gcloud compute firewall-rules delete allow-ssh-from-internet \
--project=<project-id>
# Allow inbound HTTPS only to the load balancer tier
gcloud compute firewall-rules create allow-https-lb \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=100 \
--action=ALLOW \
--rules=tcp:443 \
--source-ranges=0.0.0.0/0 \
--target-tags=load-balancer

# Allow app tier to receive from load balancer only (using network tags)
gcloud compute firewall-rules create allow-app-from-lb \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=200 \
--action=ALLOW \
--rules=tcp:8080 \
--source-tags=load-balancer \
--target-tags=app-server

# Allow data tier to receive from app tier only
gcloud compute firewall-rules create allow-db-from-app \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=300 \
--action=ALLOW \
--rules=tcp:5432 \
--source-tags=app-server \
--target-tags=db-server

# Deny all other inbound (implicit in GCP, but make it explicit for audit visibility)
gcloud compute firewall-rules create deny-all-ingress-explicit \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=65534 \
--action=DENY \
--rules=all \
--source-ranges=0.0.0.0/0

# Allow Google health check ranges (required for load balancers)
gcloud compute firewall-rules create allow-health-checks \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=50 \
--action=ALLOW \
--rules=tcp \
--source-ranges=35.191.0.0/16,130.211.0.0/22 \
--target-tags=app-server

Reference: VPC firewall rules → · Firewall policies →


3. Identity-Aware Proxy (IAP) — Secure Admin Access​

IAP replaces VPN and bastion hosts for accessing internal GCP resources. It verifies identity and context before allowing TCP tunnel access — no admin ports need to be open to the internet.

# Enable IAP for TCP tunneling (replaces SSH/RDP over the internet)
gcloud services enable iap.googleapis.com \
--project=<project-id>

# Create the firewall rule allowing IAP's IP range only for SSH
gcloud compute firewall-rules create allow-ssh-iap \
--project=<project-id> \
--network=prod-vpc \
--direction=INGRESS \
--priority=100 \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20 \
--target-tags=app-server

# Grant a user IAP tunnel access to a specific VM
gcloud projects add-iam-policy-binding <project-id> \
--member="user:[email protected]" \
--role="roles/iap.tunnelResourceAccessor"

# Connect to a VM via IAP (no public IP required)
gcloud compute ssh vm-prod \
--tunnel-through-iap \
--project=<project-id> \
--zone=us-central1-a

Reference: Identity-Aware Proxy → · IAP TCP forwarding →


4. Cloud Armor — Web Application Firewall​

Cloud Armor protects external HTTPS load balancers from OWASP Top 10 attacks, DDoS, and IP-based threats. Required for CC6.6 external threat protection.

# Create a Cloud Armor security policy in prevention mode
gcloud compute security-policies create prod-waf-policy \
--description="SOC 2 WAF policy — OWASP Top 10 protection" \
--project=<project-id>

# Enable the pre-configured OWASP Top 10 rule set
gcloud compute security-policies rules create 1000 \
--security-policy=prod-waf-policy \
--expression="evaluatePreconfiguredExpr('xss-v33-stable')" \
--action=deny-403 \
--description="Block XSS attacks"

gcloud compute security-policies rules create 1001 \
--security-policy=prod-waf-policy \
--expression="evaluatePreconfiguredExpr('sqli-v33-stable')" \
--action=deny-403 \
--description="Block SQL injection"

gcloud compute security-policies rules create 1002 \
--security-policy=prod-waf-policy \
--expression="evaluatePreconfiguredExpr('rce-v33-stable')" \
--action=deny-403 \
--description="Block RCE attempts"

gcloud compute security-policies rules create 1003 \
--security-policy=prod-waf-policy \
--expression="evaluatePreconfiguredExpr('lfi-v33-stable')" \
--action=deny-403 \
--description="Block LFI attacks"

# Attach the security policy to the backend service
gcloud compute backend-services update prod-backend \
--security-policy=prod-waf-policy \
--global \
--project=<project-id>

# Verify the policy is attached
gcloud compute backend-services describe prod-backend \
--global \
--format="value(securityPolicy)" \
--project=<project-id>

Reference: Cloud Armor documentation → · Pre-configured WAF rules →


5. Private Google Access and VPC Service Controls​

Private Google Access allows VMs without external IPs to reach Google APIs (Cloud Storage, BigQuery, Secret Manager) over Google's internal network.

VPC Service Controls creates a security perimeter around GCP services to prevent data exfiltration — even if credentials are compromised.

# Enable Private Google Access on a subnet
gcloud compute networks subnets update snet-app \
--region=us-central1 \
--enable-private-ip-google-access \
--project=<project-id>

# Create a VPC Service Controls perimeter (restricts data movement)
gcloud access-context-manager perimeters create prod-perimeter \
--title="Production Service Perimeter" \
--resources="projects/<project-number>" \
--restricted-services="storage.googleapis.com,bigquery.googleapis.com,secretmanager.googleapis.com" \
--policy=<access-policy-id>

# Verify Private Google Access is enabled
gcloud compute networks subnets describe snet-app \
--region=us-central1 \
--format="value(privateIpGoogleAccess)" \
--project=<project-id>

Reference: Private Google Access → · VPC Service Controls →


6. TLS Enforcement​

# Create a strict SSL policy (TLS 1.2+, modern cipher suites)
gcloud compute ssl-policies create prod-ssl-policy \
--profile=MODERN \
--min-tls-version=TLS_1_2 \
--project=<project-id>

# Apply the SSL policy to an HTTPS target proxy
gcloud compute target-https-proxies update prod-https-proxy \
--ssl-policy=prod-ssl-policy \
--project=<project-id>

# Enforce HTTPS-only access to Cloud Storage buckets
# (set uniform bucket-level access and deny allUsers on http)
gcloud storage buckets update gs://prod-bucket \
--uniform-bucket-level-access

# Use Organization Policy to enforce secure transport on GCS
gcloud resource-manager org-policies set-policy \
--organization=<org-id> \
- <<'EOF'
name: organizations/<org-id>/policies/storage.requireTls
spec:
rules:
- enforce: true
EOF

Reference: SSL policies → · Cloud Storage retention and access →


SOC 2 Evidence for Network Security​

Evidence itemHow to collect
VPC and subnet configurationgcloud compute networks list, gcloud compute networks subnets list
Firewall rules for all VPCsgcloud compute firewall-rules list --project=<id>
VPC Flow Logs configurationgcloud compute networks subnets list --format="table(name,enableFlowLogs)"
Cloud Armor policy and rulesgcloud compute security-policies describe prod-waf-policy
IAP configuration and access grantsgcloud compute firewall-rules list --filter="sourceRanges:35.235.240.0"
SSL policygcloud compute ssl-policies describe prod-ssl-policy
VPC Service Controls perimetersgcloud access-context-manager perimeters list
SCC network misconfiguration findingsGCP Console → Security Command Center → Findings → Category: Firewall