IAM cannot stop a valid credential from copying data to an outside project; perimeters can.
IAM answers who may call an API. VPC Service Controls (VPC SC) adds where data may go. A service perimeter surrounds a set of projects and a list of restricted services (e.g. storage.googleapis.com, bigquery.googleapis.com). Calls to those services are allowed only when both the caller's context and the target resources are inside the perimeter.
That blocks classic exfiltration paths: a stolen credential used from the internet, copying a bucket to an attacker's project, or a BigQuery query writing to an outside dataset. Violations fail with an error mentioning vpcServiceControlsUniqueIdentifier and are logged as Policy Denied audit logs.
Building blocks, managed through Access Context Manager in an org-level access policy:
- Access levels: conditions on IP ranges, device posture or identities that may enter from outside.
- Ingress and egress rules: precise exceptions (this service account may read from that external project's bucket).
- Perimeter bridges for sharing between perimeters; restricted.googleapis.com VIP plus DNS so VPC traffic stays on the restricted endpoint.
Rollout is the hard part. Many workflows touch services across projects (Cloud Build, logging sinks, Marketplace, third-party SaaS). Always start with a dry-run perimeter, study the dry-run violation logs for weeks, add ingress/egress rules, then enforce. VPC SC complements IAM and org policy; it does not replace them.
Example
POLICY=$(gcloud access-context-manager policies list --organization=555555555555 --format="value(name)")
# 1. Dry run: log violations without blocking anything
gcloud access-context-manager perimeters dry-run create shop_data --policy=$POLICY \
--perimeter-title="Shop data" --perimeter-type=regular \
--perimeter-resources=projects/987654321098,projects/444455556666 \
--perimeter-restricted-services=storage.googleapis.com,bigquery.googleapis.com
# 2. Review would-be denials
gcloud logging read 'protoPayload.metadata.dryRun="true" AND
protoPayload.metadata."@type"="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"' \
--project=shop-dev-4821 --freshness=7d --limit=20
# 3. Enforce once clean
gcloud access-context-manager perimeters dry-run enforce shop_data --policy=$POLICYRemember
- Perimeters restrict Google API data flows across a project boundary
- Access levels and ingress/egress rules are the controlled exceptions
- Always roll out in dry-run mode first
Watch out for
- Enforcing a perimeter directly and breaking CI, log sinks and cross-project jobs you did not know existed.