Create a VPC Service Controls Perimeter to Shield BigQuery from Exfiltration
Data exfiltration from BigQuery often happens through valid credentials. Learn how to build a VPC Service Controls perimeter that blocks unauthorized access while allowing trusted services through ingress and egress rules.
20 Jun 2026, 23:42 UTC

The problem: valid credentials can still leak data
When a service account with BigQuery read access is compromised, IAM permissions alone do not stop an attacker from running a broad query and exporting the results. VPC Service Controls adds a network-level boundary around Google Cloud APIs so that even valid credentials cannot reach protected datasets from outside the perimeter. This guide shows how to build a perimeter that shields BigQuery while letting specific trusted services through.
Desired outcome
You want a VPC Service Controls perimeter that includes the projects or folders containing your BigQuery datasets, restricts the BigQuery API, and allows only explicitly listed service accounts to query or export data. Optionally, you want egress rules that permit exports to a sanctioned Cloud Storage bucket while blocking all other destinations.
Prerequisites
- Organization Administrator or VPC Service Controls Admin role at the organization level.
- Access Context Manager API enabled.
- The numeric project or folder ID that contains the BigQuery datasets.
- The email addresses of trusted service accounts, such as a Cloud Run runtime service account.
- A non-production project or folder to test changes first.
Focused procedure
1. Create the perimeter shell
Run the following in Cloud Shell or any environment with the Google Cloud CLI. You need the VPC Service Controls Admin role. Replace PROJECT_NUMBER with your numeric project ID and POLICY_ID with your organization’s access policy ID.
gcloud access-context-manager perimeters create bigquery_shield \ --title="BigQuery Data Shield" \ --description="Blocks unauthorized BigQuery access" \ --perimeter-type=regular \ --resources=projects/PROJECT_NUMBER \ --restricted-services=bigquery.googleapis.com \ --policy=POLICY_ID
Expected check: List perimeters to confirm creation.
gcloud access-context-manager perimeters list --policy=POLICY_ID
Relevant risk: Creating an enforced perimeter immediately blocks all external access to BigQuery. Test in a non-production project first.
2. Allow trusted ingress
By default, the perimeter denies all external access to the restricted BigQuery API. To allow a trusted service account, add an ingress rule in the Cloud Console under Security > VPC Service Controls. Select the perimeter, add an ingress policy, and specify the allowed identity and service.
For example, to allow a Cloud Run service account to call BigQuery, the ingress rule resembles this structure:
{
"ingressFrom": {
"identities": [
"serviceAccount:SA_EMAIL"
],
"identityType": "ANY_IDENTITY"
},
"ingressTo": {
"operations": [
{
"serviceName": "bigquery.googleapis.com"
}
],
"resources": ["*"]
}
}
Replace SA_EMAIL with the trusted service account email. If you need tighter control, add methodSelectors to limit the rule to specific BigQuery methods.
3. Add egress rules for sanctioned exports
If protected BigQuery data must be exported to an approved Cloud Storage bucket, add an egress policy in the Console. Specify the source identity, the BigQuery export operation, and the destination bucket resource. All other egress paths remain blocked.
| Rule type | Direction | Typical use |
|---|---|---|
| Ingress | Into the perimeter | Allow a trusted service account to query BigQuery |
| Egress | Out of the perimeter | Allow BigQuery export to a sanctioned Cloud Storage bucket |
4. Save and monitor
Save the perimeter configuration. Perimeter updates may take a few minutes to propagate. Allow a brief window before verifying the new policy.
Expected checks
- From an authorized service account listed in the ingress policy, run a simple BigQuery query such as
SELECT 1and confirm it succeeds. - From a service account not listed in the ingress policy, attempt the same query and verify that the request is rejected with a
PERMISSION_DENIEDerror. - Check Cloud Audit Logs for VPC Service Controls denials to ensure unexpected traffic is blocked.
- If egress rules are configured, attempt to export a query result to an allowed Cloud Storage bucket and confirm success; try exporting to a disallowed bucket and confirm failure.
Recovery options
If legitimate requests are blocked, first confirm that every required service account is explicitly listed in the ingress policies. Missing identities are the most common cause of PERMISSION_DENIED errors.
If the perimeter is too restrictive in production, switch it to dry-run mode to log violations without blocking traffic, adjust the rules, and then re-enable enforcement. In an emergency, deleting the perimeter removes the boundary entirely, but this is a state-changing operation that exposes the datasets and should be a last resort.
Limitations
- VPC Service Controls does not protect data at rest within BigQuery. Combine it with CMEK or other encryption controls for full data protection.
- The perimeter does not prevent exfiltration by identities that are already inside the boundary.
- All required service accounts must be explicitly listed; a single omission can break legitimate workloads.
- Perimeter updates propagate asynchronously, so allow a brief window before verifying the new policy.
Practical way to check the result
Use gcloud access-context-manager perimeters describe PERIMETER_NAME --policy=POLICY_ID to confirm the resources and restricted services. Then run the positive and negative query tests described above. Finally, review Cloud Audit Logs for vpc.access denial entries to confirm the perimeter is enforcing as expected.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.