GCP for DevOps — VPC Service Controls

2 minute read

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

Updated: