VPC Service Controls Without Private IP Coverage Is Security Theater
Most GCP teams I work with have VPC Service Controls enabled. They check the compliance box, show auditors the perimeter configuration, and move on. What they don't realize is that their internal services can still exfiltrate data to external projects without triggering a single alert.
The gap isn't in VPC-SC itself — it's in how teams deploy it. Private IP support in VPC-SC perimeters has been available for a while now, but I'd estimate fewer than 20% of the SaaS platforms I audit have actually implemented it. The rest have a perimeter that looks solid on paper but leaves the most common exfiltration path wide open.
The Exfiltration Path Nobody Talks About
VPC Service Controls were designed to prevent data from leaving your GCP organization through managed services like BigQuery, Cloud Storage, and Secret Manager. The original implementation worked well for public internet traffic — if someone tried to copy data from your BigQuery dataset to an external project over the public API, VPC-SC blocked it.
But traffic originating from private IP ranges inside your VPC? That wasn't covered.
Think about what that means in practice. An attacker compromises a service account on a GKE workload running in your private network. They have access to BigQuery through that identity. With VPC-SC but without private IP coverage, they can query your datasets and write the results to an external project they control — all from inside your "protected" perimeter.
I've seen this exact scenario during penetration tests. The security team was confident their VPC-SC perimeter would catch any data exfiltration attempt. It didn't. The test showed data flowing out through internal services that the perimeter didn't inspect.
Why This Gap Persists
Three patterns explain why most teams haven't closed this gap:
Dry-run mode paralysis. VPC-SC is notoriously difficult to enforce without breaking production services. The safe approach is to run in dry-run mode first, watch the logs, and then switch to enforced. I've seen teams run in dry-run mode for six months or longer. At that point, dry-run becomes the permanent state — and dry-run mode doesn't actually block anything. It just logs what would have been blocked. That's monitoring, not protection.
Incomplete perimeter design. Teams enable VPC-SC for BigQuery and Cloud Storage but skip Secret Manager, Cloud SQL Admin API, or other services that handle sensitive data. Attackers don't care which service holds your data — they'll take whatever path is open.
Misconfigured ingress and egress rules. Once private IP support is enabled, you need explicit ingress rules allowing legitimate internal traffic. Most teams either make these rules too broad (defeating the purpose) or too narrow (breaking production). The operational burden pushes teams toward permissive configurations or abandoning the feature entirely.
The Architecture That Actually Works
In my experience, closing the data exfiltration gap requires three components working together:
VPC-SC with private IP coverage. Configure your perimeter to inspect traffic from internal CIDR ranges, not just public internet traffic. This is the foundation.
Access Context Manager access levels tied to network origin and identity. Don't just allow traffic from a private IP range — require that traffic to also come from a specific service account. Defense in depth means an attacker needs to compromise both the network position and the identity.
Ingress rules scoped to specific services and methods. If your data pipeline only needs to read from BigQuery, don't grant write access through the perimeter. Principle of least privilege applies to network perimeters just like it applies to IAM.
Here's what a properly scoped ingress rule looks like in practice:
ingressPolicies:
- ingressFrom:
sources:
- resource: "projects/YOUR_PROJECT"
identities:
- serviceAccount:data-pipeline@project.iam.gserviceaccount.com
ingressTo:
operations:
- serviceName: bigquery.googleapis.com
methodSelectors:
- method: "google.cloud.bigquery.v2.JobService.Query"
resources:
- "projects/YOUR_PROJECT/datasets/production_data"
This rule allows one service account to run queries against one dataset. An attacker who compromises a different service account — or the same service account trying to write data externally — gets blocked.
The Terraform resource for managing this is google_access_context_manager_service_perimeter. I'd recommend managing all perimeter configuration through infrastructure as code. Manual console changes to VPC-SC perimeters are a recipe for configuration drift and broken production services.
What This Means for SOC 2 and Audit Readiness
During SOC 2 audits, I've had auditors ask specifically about data exfiltration controls. "Show me how you prevent an insider or compromised credential from copying data outside your organization."
VPC-SC without private IP coverage doesn't answer that question. You can show them the perimeter configuration, but if private IP traffic isn't covered, you have a control gap. Auditors who understand GCP will catch it. Auditors who don't will accept the checkbox — until you have an incident and the forensics reveal the gap.
This is where the security-by-design principle from the SCALE framework matters most. If you build your perimeter architecture correctly from the start, SOC 2 evidence collection is straightforward. If you retrofit private IP coverage onto an existing perimeter, you're doing the work twice and risking production outages during the transition.
The Trade-Offs Are Real
I'm not going to pretend VPC-SC with full private IP coverage is easy to operate. It adds friction to every new service deployment. Your platform team will field tickets from developers asking why their new Cloud Function can't reach BigQuery. The answer will be "because you didn't add it to the perimeter ingress rules," and that will slow down their sprint.
The CIDR planning requirements are also non-trivial. If you have overlapping IP ranges across projects — common in organizations that grew without central network governance — you'll hit routing issues that are painful to debug.
And not all GCP services support VPC-SC yet. Before designing your perimeter architecture, check the supported services list. Building a perimeter around services that don't support it creates gaps you can't close with configuration.
The Enforcement Question
If your VPC-SC perimeter has been in dry-run mode for more than a month, you need to ask yourself an honest question: is it ever going to be enforced?
Dry-run mode is valuable for the first two weeks. You watch the logs, identify legitimate traffic that would be blocked, and adjust your ingress and egress rules. After that, you either enforce the perimeter or admit that you're not actually protecting anything.
I've worked with teams who ran dry-run mode for eight months because they were afraid of breaking production. During that time, they had zero data exfiltration protection. The perimeter existed on paper. In practice, it was monitoring, not security.
Data exfiltration is the top concern in every regulated SaaS environment I work with. Your customers trust you with their data. VPC-SC with private IP support is one of the few controls that actually prevents data from leaving your organization through GCP's managed services.
If you've been putting off this work, the gap is still open. What's your plan to close it?
Work with a GCP specialist — book a free discovery call.
Amit Malhotra
Principal GCP Architect, Buoyant Cloud Inc
Work with a GCP specialist — book a free discovery call → https://buoyantcloudtech.com
Top comments (0)