A common security baseline on Google Cloud says that virtual machines, GKE nodes and other workloads should not have external IP addresses. The first thing that breaks is access to Google's own APIs: a VM that cannot reach the internet cannot reach storage.googleapis.com either, because those APIs live on public addresses. Pipelines stop reading Cloud Storage, nodes cannot pull images and agents cannot write logs.
Google Cloud offers two families of fixes that are often confused. Private Google Access (PGA) is a per-subnet switch that lets internal-only VMs reach Google APIs over Google's network. Private Service Connect (PSC) puts an internal IP address from your own address plan in front of Google APIs, or in front of a service published by another VPC network, another team or a vendor. This article explains how each works, how to configure them with DNS and routes, how they reach on-premises networks, how they differ from Cloud NAT and private services access, and what breaks in practice. For the underlying network model see Google Cloud VPC.
The problem and the options
A VM with only an internal address has no path to the internet. There are four ways to let it reach Google APIs or other managed services, and they solve different problems:
| Option | What it gives you | Address the client uses |
|---|---|---|
| Cloud NAT | General outbound internet access, including Google APIs | Public Google addresses, translated to NAT IPs |
| Private Google Access | Google APIs only, from internal-only VMs in enabled subnets | Google's public VIPs or the private and restricted VIP ranges |
| PSC endpoint for Google APIs | Google APIs through an internal IP you choose | An internal IP in your VPC |
| PSC endpoint for a published service | One producer service, exposed privately | An internal IP in your subnet |
A fifth mechanism, private services access, is different again: it is a VPC peering between your network and a Google-managed service producer network, used by services such as Cloud SQL private IP. It does not give you access to Google APIs such as Cloud Storage. Keep the three names apart: Private Google Access, private services access and Private Service Connect.
How Private Google Access works
Private Google Access is enabled per subnet. When it is on, a VM interface in that subnet without an external IP can send traffic to Google APIs and services, and the traffic stays on Google's network. Google's documentation lists four requirements: the interface is in a subnet with PGA enabled, the interface has no external IP (if it has one, it reaches Google directly and PGA does not apply), the VPC has routes to the Google API addresses whose next hop is the default internet gateway, and firewall rules allow egress to those addresses.
The route requirement surprises people. The next hop is named default internet gateway, but for PGA traffic it does not mean the public internet. It is how the VPC hands packets for Google's API addresses to Google's front ends. If your organisation has deleted the default 0.0.0.0/0 route, as many hardened designs do, PGA stops working for the default domains until you add narrower routes for the addresses your DNS returns.
Clients can use three sets of domain names:
| Domain | IPv4 range | What it serves |
|---|---|---|
Default domains (storage.googleapis.com, ...) | Google's public API addresses | All APIs; needs a route covering those public ranges |
private.googleapis.com | 199.36.153.8/30 | Most Google APIs, including ones not supported by VPC Service Controls |
restricted.googleapis.com | 199.36.153.4/30 | Only APIs supported by VPC Service Controls |
The private and restricted domains have small, fixed ranges, which makes routes, firewall rules and on-premises advertisements simple. The restricted domain is the one to use with a service perimeter, because it cannot reach APIs outside VPC Service Controls; see VPC Service Controls. Both also have IPv6 ranges, listed in Google's documentation. Google's PGA documentation additionally asks for routes and firewall rules to 34.126.0.0/18 for its direct connectivity services; check the current page for whether your services need it.
A worked example: an internal-only VPC reaching Cloud Storage
Take a VPC called prod-vpc with a subnet app-subnet in europe-west1. The security team has removed the default route, denied all egress by default and forbidden external IPs. A batch job on a VM must read from a Cloud Storage bucket. Using the private VIP, the configuration is a subnet flag, one route, one firewall rule and a private DNS zone:
# 1. Enable Private Google Access on the subnet
gcloud compute networks subnets update app-subnet --region=europe-west1 \
--enable-private-ip-google-access
# 2. Route the private.googleapis.com VIP via the default internet gateway
# (needed when the 0.0.0.0/0 default route has been removed)
gcloud compute routes create pga-private-vip --network=prod-vpc \
--destination-range=199.36.153.8/30 --next-hop-gateway=default-internet-gateway
# 3. Allow HTTPS egress to the VIP if egress is denied by default
gcloud compute firewall-rules create allow-egress-pga --network=prod-vpc \
--direction=EGRESS --action=ALLOW --rules=tcp:443 \
--destination-ranges=199.36.153.8/30 --priority=900
# 4. Private DNS: send *.googleapis.com to the VIP
gcloud dns managed-zones create googleapis --dns-name=googleapis.com. \
--visibility=private --networks=prod-vpc --description="PGA VIP"
gcloud dns record-sets create private.googleapis.com. --zone=googleapis --type=A --ttl=300 \
--rrdatas=199.36.153.8,199.36.153.9,199.36.153.10,199.36.153.11
gcloud dns record-sets create "*.googleapis.com." --zone=googleapis --type=CNAME --ttl=300 \
--rrdatas=private.googleapis.com.
# 5. Verify from a VM in the subnet
dig +short storage.googleapis.com # expect 199.36.153.8-11
gcloud storage ls gs://my-bucket/The DNS zone is what makes this work for unmodified clients. Client libraries and gcloud call storage.googleapis.com as usual; the private zone attached to prod-vpc answers with a CNAME to private.googleapis.com, which resolves to the four VIP addresses. The route carries packets for that /30 to Google, the firewall allows them, and TLS still validates because the certificate is for the name the client requested. No code changes and no public IP are involved, and IAM authorisation is unchanged (see Google Cloud IAM).
One caveat on the wildcard: it covers *.googleapis.com only. Other Google domains that some tools use, such as container and artifact registries on their own domains, need their own private zones pointing to the same VIP if the service supports it.
Private Service Connect endpoints for Google APIs
A PSC endpoint for Google APIs gives Google APIs an internal IP address that you choose. You reserve a global internal address with purpose PRIVATE_SERVICE_CONNECT, then create a global forwarding rule that targets an API bundle: all-apis for all supported APIs, or vpc-sc for only those supported by VPC Service Controls. Registration in Service Directory is optional via --service-directory-registration.
# PSC endpoint for Google APIs: an internal IP you choose, reserved as a GLOBAL address
gcloud compute addresses create psc-apis-ip --global \
--purpose=PRIVATE_SERVICE_CONNECT --addresses=10.10.0.5 --network=prod-vpc
gcloud compute forwarding-rules create pscapis --global --network=prod-vpc \
--address=psc-apis-ip --target-google-apis-bundle=all-apis
# DNS names such as storage-pscapis.p.googleapis.com now resolve to 10.10.0.5
# Producer: publish an internal load balancer through a service attachment
gcloud compute networks subnets create psc-nat --network=producer-vpc \
--region=europe-west1 --range=10.99.0.0/24 --purpose=PRIVATE_SERVICE_CONNECT
gcloud compute service-attachments create orders-api --region=europe-west1 \
--target-service=projects/prod-p/regions/europe-west1/forwardingRules/orders-ilb \
--connection-preference=ACCEPT_MANUAL --nat-subnets=psc-nat \
--consumer-accept-list=consumer-project-a=10
# Consumer: a regional endpoint in its own subnet, pointing at the attachment
gcloud compute addresses create orders-ep-ip --region=europe-west1 --subnet=app-subnet
gcloud compute forwarding-rules create orders-ep --region=europe-west1 --network=consumer-vpc \
--address=orders-ep-ip \
--target-service-attachment=projects/prod-p/regions/europe-west1/serviceAttachments/orders-apiCreating the endpoint creates DNS names of the form SERVICE-ENDPOINT.p.googleapis.com: an endpoint named pscapis gives storage-pscapis.p.googleapis.com, bigquery-pscapis.p.googleapis.com and so on, resolving to your chosen IP. Clients can use those names directly, or you can point a private googleapis.com zone at the endpoint IP as in the PGA example. Endpoint names must be 1 to 20 characters of lowercase letters and digits, starting with a letter.
Why choose PSC over PGA with the private VIP? The address is yours, so it fits an address plan, firewall rules and on-premises routing without referring to Google-owned ranges. You can create several endpoints, for example one with all-apis and one with vpc-sc, and steer different workloads to each through DNS. Two limits matter: endpoints are not reachable from peered VPC networks, and an endpoint for Google APIs cannot be updated after creation, so changing its bundle or address means creating a new one and moving DNS.
Private Service Connect for published services
The same mechanism connects consumers to services that another network publishes, whether that is a platform team's internal API, a managed database vendor or a partner. The producer puts the service behind a supported internal load balancer, such as an internal passthrough Network Load Balancer, a regional or cross-region internal Application Load Balancer or a regional internal proxy Network Load Balancer, and creates a service attachment. The attachment needs a subnet with purpose PRIVATE_SERVICE_CONNECT, from which it takes source addresses for consumer traffic. The consumer creates a regional endpoint with an internal IP in its own subnet that targets the attachment.
Three properties explain why teams prefer this to VPC peering. The networks never exchange routes, so overlapping address ranges are fine and the consumer sees one IP, not the producer's subnets. Connections are one-way: consumers can reach the service, but the producer cannot initiate connections into the consumer network. And the producer controls who connects: with ACCEPT_MANUAL and a consumer accept list, each connection is accepted per project or network with a connection limit, and endpoints move through PENDING, ACCEPTED, REJECTED or CLOSED. Traffic flows only once an endpoint is ACCEPTED.
Because the producer sees traffic from its PSC NAT subnet, it loses the consumer's source address. The --enable-proxy-protocol option prepends a PROXY protocol header carrying connection information for TCP services that need it, and the backends must be configured to expect it. Consumer endpoints are regional by default; --allow-psc-global-access lets clients in other regions use them, and Google advises enabling it only when the producer's load balancer is configured for global access. The equivalent AWS and Azure mechanisms are compared in cloud private link services.
Reaching Google APIs from on-premises
On-premises hosts connected by Cloud VPN or Cloud Interconnect can use the same paths. For PGA, advertise the private or restricted VIP range to on-premises from Cloud Router using custom route advertisements, make sure the VPC has routes for that range with the default internet gateway as next hop, and make on-premises DNS resolve the Google API names to the VIP. If Cloud DNS answers those queries, forward googleapis.com from on-premises resolvers to a Cloud DNS inbound forwarder in the same region as the VPN tunnel or VLAN attachment. For PSC, advertise the endpoint's internal IP instead, which is easier to fit into an existing on-premises firewall policy.
Failure modes
- Default route removed, default domains in use. PGA needs a route to whatever addresses DNS returns. With
0.0.0.0/0gone and no private zone, API calls time out. Add the VIP route and DNS zone, or a PSC endpoint. - Restricted VIP for an unsupported API.
restricted.googleapis.comserves only APIs supported by VPC Service Controls. A wildcard CNAME to it breaks every other API with connection or DNS errors. - External IP on the VM. PGA does not apply to interfaces with external IPs; traffic takes the public path and may be blocked by egress policy you expected PGA to bypass.
- Egress deny rules. A default-deny egress policy blocks the VIP until you add an allow rule for its range on TCP 443.
- PSC from a peered VPC. Endpoints for Google APIs are not reachable across VPC peering; create endpoints in each network or use Shared VPC.
- Endpoint stuck in PENDING. The producer uses manual acceptance and the consumer project is not in its accept list.
- NAT subnet exhaustion. The producer's PSC subnet provides source addresses for consumer connections; size it for growth and watch its utilisation.
- On-premises DNS forwarding to the wrong region. The inbound forwarder must be in the region of the tunnel or attachment carrying the queries.
Operational guidance and trade-offs
Pick one pattern per environment and write it down. For most internal-only estates, PGA with private.googleapis.com and a private DNS zone is the lightest option. Use restricted.googleapis.com or a vpc-sc PSC endpoint inside a service perimeter. Choose PSC endpoints when addresses must come from your own plan, when on-premises routing policy is strict, or when different workloads need different bundles. Use PSC for published services instead of peering whenever two teams or organisations need a narrow, one-way dependency. PSC endpoints are billed resources, so check current pricing; Cloud NAT remains the answer for general internet egress.
Verify with tools rather than assumptions. Connectivity Tests in Network Intelligence Center can trace a path from a VM to a VIP or endpoint IP and name the route or firewall rule that drops it. VPC Flow Logs show whether traffic is going to the VIP, the PSC endpoint or somewhere else. An organisation policy that forbids external IPs makes the private paths mandatory rather than optional.
What to do next
- Inventory which Google APIs and hostnames your internal-only workloads call, including registries and agents.
- Choose per environment: PGA with the private VIP, the restricted VIP inside a perimeter, or PSC endpoints with your own IPs.
- Enable PGA on the subnets, add routes and egress rules for the chosen range, and create the private DNS zone.
- Check resolution with
digand access withgcloud storage lsfrom a VM with no external IP. - For on-premises, add Cloud Router custom advertisements and DNS forwarding to an inbound forwarder in the right region.
- Replace cross-team VPC peering with PSC service attachments where the dependency is one-way.
- Codify everything in Terraform and add a Connectivity Test to your change pipeline.