GCP for DevOps — VPC Service Controls
VPC Service Controls
VPC Service Controls create security perimeters around GCP resources to prevent data exfiltration. They restrict which networks, identities, and projects can access services like Cloud Storage, BigQuery, and Pub/Sub.
How VPC Service Controls Work
VPC Service Controls:
┌────────────────────────────────────────┐
│ Service Perimeter │
│ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Project A │ │ Cloud Storage │ │
│ │ │──│ BigQuery │ │
│ │ VMs, GKE │ │ Pub/Sub │ │
│ └──────────┘ └──────────────────┘ │
│ │
│ ┌──────────┐ ✓ Allowed │
│ │ Project B │──────▶ (inside) │
│ └──────────┘ │
│ │
└────────────────────────────────────────┘
▲
│ ✗ Blocked (outside perimeter)
│
┌──────────┐
│ External │
│ Project │
└──────────┘
Create an Access Policy
# Create an access policy (org level, usually done once)
$ gcloud access-context-manager policies create \
--organization=123456789 \
--title="My Org Policy"
# List policies
$ gcloud access-context-manager policies list \
--organization=123456789
Create Access Levels
Access levels define conditions under which access is allowed:
# Create an access level for corporate network
$ gcloud access-context-manager levels create corp-network \
--policy=POLICY_ID \
--title="Corporate Network" \
--basic-level-spec=corp-level.yaml
# corp-level.yaml
conditions:
- ipSubnetworks:
- "203.0.113.0/24"
- "198.51.100.0/24"
- members:
- "user:admin@example.com"
- "serviceAccount:ci-cd@my-project.iam.gserviceaccount.com"
Create Service Perimeters
# Create a service perimeter
$ gcloud access-context-manager perimeters create data-perimeter \
--policy=POLICY_ID \
--title="Data Protection Perimeter" \
--resources="projects/123,projects/456" \
--restricted-services="storage.googleapis.com,bigquery.googleapis.com" \
--access-levels="accessPolicies/POLICY_ID/accessLevels/corp-network"
# Dry-run mode (test without enforcing)
$ gcloud access-context-manager perimeters dry-run create test-perimeter \
--policy=POLICY_ID \
--resources="projects/123" \
--restricted-services="storage.googleapis.com"
# List perimeters
$ gcloud access-context-manager perimeters list --policy=POLICY_ID
# Update a perimeter (add a project)
$ gcloud access-context-manager perimeters update data-perimeter \
--policy=POLICY_ID \
--add-resources="projects/789"
Ingress and Egress Rules
# Allow specific external access (ingress)
ingressPolicies:
- ingressFrom:
identities:
- "serviceAccount:external-ci@other-project.iam.gserviceaccount.com"
sources:
- accessLevel: "accessPolicies/POLICY_ID/accessLevels/corp-network"
ingressTo:
operations:
- serviceName: "storage.googleapis.com"
methodSelectors:
- method: "google.storage.objects.get"
resources:
- "projects/123"
# Allow data to flow to specific external destination (egress)
egressPolicies:
- egressFrom:
identities:
- "serviceAccount:export-sa@my-project.iam.gserviceaccount.com"
egressTo:
operations:
- serviceName: "storage.googleapis.com"
resources:
- "projects/external-backup-project"
Commonly Protected Services
| Service | Why Protect |
|---|---|
storage.googleapis.com |
Prevent bucket data exfiltration |
bigquery.googleapis.com |
Prevent query result export |
secretmanager.googleapis.com |
Protect secrets from external access |
container.googleapis.com |
Protect GKE clusters |
cloudfunctions.googleapis.com |
Protect function source/data |
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
| No dry-run testing | Breaks CI/CD on enforce | Always test in dry-run first |
| Too broad perimeter | Hard to manage | Group related projects only |
| Missing ingress rules | CI/CD can’t access resources | Add service account ingress rules |
| Not protecting all services | Partial protection | Add all data services |
| No access levels | Only network-based | Combine identity + network conditions |
Quick Reference
| Command | Description |
|---|---|
gcloud access-context-manager perimeters create |
Create perimeter |
gcloud access-context-manager perimeters update |
Update perimeter |
gcloud access-context-manager levels create |
Create access level |
gcloud access-context-manager perimeters dry-run create |
Dry-run perimeter |
gcloud access-context-manager perimeters list |
List perimeters |
Next → Binary Authorization