Skip to content

Private Service Connect to Vertex AI From Another VPC

10 min read · updated August 11, 2026

Two things have to be true before a call to aiplatform.googleapis.com stays inside Google’s network: an internal address that forwards to the API, and a resolver that returns that address instead of the public one. Building the first and skipping the second is the single most common way this ends with traffic still going out the front door.

What a PSC endpoint for Google APIs is

Private Service Connect covers two different things and the docs use the same name for both. One is a PSC endpoint targeting a service attachment, which is how you reach a specific published service — including a Vertex AI online prediction endpoint deployed as a dedicated private endpoint. The other, and the one this page builds, is a PSC endpoint targeting a bundle of Google APIs: a global forwarding rule with an internal address that answers for the whole *.googleapis.com surface, Vertex AI included.

Google documents two bundle values for the target. all-apis reaches supported Google APIs and is the equivalent of private.googleapis.com; vpc-sc reaches only APIs supported by VPC Service Controls and is the equivalent of restricted.googleapis.com (Google Cloud, Private Service Connect for generative AI on Vertex AI). Choose vpc-sc if you are inside a service perimeter and want exfiltration to a non-perimeter project to fail at the network layer; choose all-apis otherwise, and know that it reaches every supported Google API, not only Vertex.

The choice matters because it is baked into the forwarding rule at creation. Switching later means deleting and recreating the rule, which is a brief outage for everything resolving through it.

Creating the endpoint

  1. Reserve a global internal address with the Private Service Connect purpose. It must not overlap any subnet range in the VPC, and it is a single address, not a range you carve later.
  2. Create a global forwarding rule that binds that address to the API bundle. This is the endpoint; there is no backend service, no health check and no load balancer to configure.
gcloud compute addresses create psc-googleapis-ip \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=10.10.0.100 \
  --network=inference-vpc

gcloud compute forwarding-rules create psc-googleapis \
  --global \
  --network=inference-vpc \
  --address=psc-googleapis-ip \
  --target-google-apis-bundle=all-apis

Confirm it exists before going further, because a typo in the network name produces a rule that is created successfully and serves nothing:

gcloud compute forwarding-rules describe psc-googleapis --global \
  --format='value(IPAddress,target,network)'
Endpoint behaviour and the set of supported APIs are documented per service and change as services are added. Check the Vertex AI page on accessing services through Private Service Connect endpoints for the current list before assuming a particular Vertex surface is covered.

The DNS half, which is not optional

At this point 10.10.0.100 works and nothing uses it, because every SDK in your fleet resolves aiplatform.googleapis.com to a public address and connects there. The endpoint takes effect only when resolution inside the VPC returns your address. That is a private Cloud DNS zone for googleapis.com, and it has to cover the wildcard, because Vertex is addressed per region — europe-west4-aiplatform.googleapis.com, not the bare name.

gcloud dns managed-zones create googleapis-psc \
  --dns-name=googleapis.com. \
  --networks=inference-vpc \
  --visibility=private \
  --description="Resolve Google APIs to the PSC endpoint"

gcloud dns record-sets create googleapis.com. \
  --zone=googleapis-psc --type=A --ttl=300 --rrdatas=10.10.0.100

gcloud dns record-sets create "*.googleapis.com." \
  --zone=googleapis-psc --type=CNAME --ttl=300 --rrdatas=googleapis.com.

A private zone for googleapis.com is authoritative for the whole name inside that VPC, which is a larger commitment than it looks: every Google API any workload in the VPC calls now resolves to this endpoint, not only Vertex. With the all-apis bundle that is fine, since the endpoint answers for all of them. With vpc-sc it is exactly the intended blast radius, but it does mean an unsupported API starts failing the moment the zone is created rather than at some later date.

For comparison, the equivalent without PSC is a zone whose records point at Google’s published virtual ranges. Google documents 199.36.153.8/30 for private.googleapis.com and 199.36.153.4/30 for restricted.googleapis.com (Google Cloud, accessing the Vertex AI API). Those are useful to know because they are the addresses an on-premises router advertises over an interconnect. A PSC endpoint replaces them with an address you chose in your own range, which is why it composes better with existing on-premises routing.

Reaching it from a different VPC

The endpoint is created in one network. A workload in a second VPC reaches it in one of three ways, and they are not interchangeable.

  • Shared VPC. The endpoint lives in the host project and every service project attached to it uses the address directly. Nothing to peer, nothing extra to resolve. This is the arrangement the feature fits best.
  • VPC Network Peering. Peered networks reach the address, but you must also bind the private DNS zone to the second network — peering carries routes, and DNS is a separate grant. Add the consumer network to the zone with gcloud dns managed-zones update --networks, or the peer resolves the public name and the whole exercise is undone.
  • Cloud Interconnect or VPN, for on-premises. The endpoint address must be advertised to the on-premises router as a custom route from Cloud Router, and on-premises resolvers need forwarding rules for googleapis.com pointing into the VPC. Both halves again: route and name.

The pattern to notice is that every one of these is two grants, and almost every report of “PSC is set up but traffic still goes over the internet” is one of them missing — the same class of problem as peering a VPC to a managed vector database.

Verifying and what breaks

Verify from a VM in the consumer network with no external address at all. That is the real test: if the instance cannot reach the public internet and the Vertex call succeeds, it went through the endpoint.

# Should return your endpoint address, not a public one.
dig +short europe-west4-aiplatform.googleapis.com

# Should succeed on a VM with no external IP and no Cloud NAT.
curl -sS -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://europe-west4-aiplatform.googleapis.com/v1/projects/$PROJECT/locations/europe-west4/publishers/google/models" \
  -o /dev/null -w '%{http_code}\n'

Two failures are worth pre-empting. Cached DNS: a long-running process that resolved the public name at start-up keeps using it, so restart the workload after creating the zone rather than wondering why half the fleet moved. And IAM: PSC changes the path, not the permission. A call that arrives privately and lacks aiplatform.endpoints.predict fails with a 403, which is a correct answer to a different question and not a networking problem.