Why architecture matters here
The architecture matters because the threat model here is not the attacker you imagine. Perimeters are not primarily about stopping an external intruder — an intruder without credentials is already stopped by IAM. They are about the credentialed path: the stolen service account key, the compromised CI runner, the contractor's laptop, the well-meaning data scientist who exports a table to a personal project to work on it over the weekend. In every one of those cases the request is authorized. The only remaining question a control can ask is about location and destination, and that is a fundamentally different question requiring a different mechanism.
It also matters because exfiltration in cloud environments is a copy, not a download. The dangerous action is rarely someone pulling a terabyte across the internet, which is slow and conspicuous. It is a bq cp from your dataset to a dataset in a project outside your organization, or a storage transfer between two buckets, both executed by Google's infrastructure at Google's internal speed. The data never traverses a network you can inspect. Only a control that sits at the API boundary and understands resource identity can see it, which is precisely why the egress half of the perimeter exists and why it is the half people forget to configure.
The structure matters because a perimeter is coarse by design and that coarseness has real consequences. It operates on projects, not on individual resources — you cannot perimeter one bucket. This forces project topology to become a security decision: projects that hold sensitive data must be separable from projects that do not, because the perimeter boundary can only be drawn where a project boundary already is. Organizations that scattered sensitive data across projects for organizational convenience discover that adopting VPC Service Controls is a project migration first and a policy exercise second.
The rollout risk is architectural rather than incidental, and it deserves respect. A perimeter denies by default, and its denials are total and immediate. Turning one on around a mature project reliably breaks things nobody knew existed: a monitoring integration, a partner's data feed, a nightly export to a analytics vendor, a support tool that reads logs. These are not misconfigurations — they are legitimate flows that nobody documented. This is why dry-run mode is not a nicety but the primary interface for adopting the product, and why treating enforcement as the starting point rather than the destination is the most expensive mistake available.
The architecture: every piece explained
The central object is the service perimeter. It has two lists that do all the work: the projects inside it, and the Google services it restricts. Restricting a service means that calls to that service's API targeting resources in those projects are subject to the boundary. A project can belong to exactly one regular perimeter, which is a constraint with real design consequences — you cannot layer overlapping perimeters, so the perimeter map and the project map must be designed together. Services not on the restricted list are unaffected, which means an unrestricted service inside a perimeter project is an open door, and the door is invisible unless you audit the list.
Ingress and egress rules are the modern way to punch precise holes. An ingress rule describes a call coming into the perimeter and has two halves that both must match: the from block, naming which identities and which sources (an access level, or another perimeter's projects) the call may originate from, and the to block, naming which services, methods, and resources may be targeted. An egress rule mirrors this for calls leaving the perimeter — from an identity inside, to a service and resource outside. The pairing is what gives these rules their precision: you can allow one service account to write to one external bucket and nothing more.
Access levels, defined in Access Context Manager, are a separate and frequently confused concept. An access level is a reusable predicate about the origin of a request: this IP range, this device policy state, this region, this identity set. Access levels do not grant perimeter access by themselves — they are referenced from the from block of an ingress rule (and from the legacy perimeter access list). The mental model that keeps this straight: an access level describes where a caller is, and an ingress rule decides what that caller may reach. Confusing the two produces policies that look right and deny everything.
The restricted VIP is the piece that makes the perimeter real for traffic originating inside your VPC. Google publishes restricted.googleapis.com on a dedicated address range, and it resolves only services that support VPC Service Controls — deliberately excluding the ones that do not, so that a VM cannot reach an unrestricted API as a side channel. Making a VM use it is DNS work: a private zone overriding googleapis.com with a CNAME to the restricted endpoint, plus routes and Private Google Access. Get the DNS wrong and traffic silently uses the public VIP, the perimeter's protection quietly does not apply to that path, and nothing tells you.
Perimeter bridges and dry-run mode round out the model. A bridge allows projects in two different perimeters to call each other, without merging the perimeters — useful for a shared logging or artifact project, and dangerous if used as a general-purpose exception because a bridge is symmetric and broad. Dry-run mode is the more important of the two: a perimeter can carry a shadow configuration that is evaluated and logged but never enforced, producing exactly the violation records enforcement would produce. That is the mechanism that turns a perimeter rollout from a guess into a measurement.
End-to-end flow
Trace a request. A service account inside a perimeter project calls bigquery.googleapis.com to read a table in that same project. The call arrives at Google's front end, which resolves the target resource to a project and asks whether that project is inside a perimeter with BigQuery restricted. It is. The call's origin is also inside the same perimeter, so no boundary is crossed. The perimeter check passes without any rule needing to exist — intra-perimeter traffic is the default-allowed case, which is the property that makes perimeters livable.
Now the same service account issues a copy of that table into a dataset in a project outside the perimeter. This is one API call, and it is where the architecture earns its keep. The perimeter evaluates the destination: the target resource lives outside. That is an egress crossing. Absent an egress rule whose from block names this identity and whose to block names this service and this destination resource, the call is denied. IAM was satisfied — the account genuinely had permission on both sides. The perimeter denied it anyway, and this is the canonical exfiltration block.
Next, an engineer on a laptop at home runs the same read against the perimeter-protected table. Their credentials are fine. But the request originates outside the perimeter, so it is an ingress crossing. The perimeter looks for an ingress rule whose from block matches — typically one referencing an access level for the corporate IP range or a managed-device policy. The coffee shop IP matches no access level, so the request is denied with a perimeter violation, not a permission denial. If the engineer connects to the corporate VPN and retries, the source IP now satisfies the access level, the ingress rule matches, and the identical request succeeds.
Consider the VM path, because it exposes the DNS subtlety. A Compute Engine instance inside a perimeter project calls Cloud Storage. If its DNS resolves storage.googleapis.com to the public VIP, the request egresses toward the public internet-facing endpoint; depending on routing it may work, may be blocked, and — the real hazard — may not be recognized as originating inside the perimeter. With the private zone in place, the name resolves to the restricted VIP, the request stays on Google's network, the origin is unambiguously the perimeter project, and the check passes cleanly. The DNS configuration is load-bearing security infrastructure, not plumbing.
Now run the same traffic against a dry-run perimeter. Every one of the above evaluations happens, and every crossing that would have been denied writes an audit entry naming the perimeter, the service, the method, the principal, and the violation reason. Nothing is blocked. Over a week, that log becomes an inventory of every real flow crossing the boundary — including the nightly vendor export nobody remembered. Each entry is then either a legitimate flow that earns an ingress or egress rule, or an unexpected flow that is a genuine finding.
The synthesis: every request is evaluated twice, against two independent questions, and the answers compose with AND. IAM asks about the principal; the perimeter asks about the crossing. Intra-perimeter traffic is free, crossings require an explicit paired rule, access levels qualify origins rather than granting access, and dry-run mode lets you observe the entire denial set before a single user is affected. Every operational practice below follows from those five facts.