Why this matters
Cloud NAT shows up in two places on a Google Cloud bill: the NAT gateway and the data it processes. Internet egress is a separate meter. A VM with no external IP uses Cloud NAT for OS patches, container pulls, package installs and calls to public APIs. That design is fine until every workload in a project shares one NAT and nobody checks what goes through it.
The cost grows with traffic volume and with the number of NAT gateways you keep running. Autoscaling GKE nodes, short lived build agents and serverless jobs can push a lot of small requests through NAT. Some of that traffic does not need to leave Google Cloud at all. Google APIs, Artifact Registry images and internal services can often use private paths.
The fix is part routing change and part hygiene. Move private traffic off NAT, cache what you download, keep chatty services in the same zone or region, and size NAT for the connections you actually need. Then watch the bill for a week to prove the change.
Before you start
Get read access to the billing account and the projects you plan to change. You need Billing Account Viewer, Project Viewer, Compute Network Viewer and Logs Viewer at minimum. To edit NAT, routers, firewall rules and DNS, you need network admin rights in each project. Ask for a change window and a rollback plan before you touch a shared NAT.
List every Cloud Router and Cloud NAT in scope, with region, NAT IP addresses, minimum ports per VM, dynamic port allocation setting and logging configuration. Check which subnets have Private Google Access turned on. Find serverless VPC connectors, Cloud Run services with VPC egress, and GKE clusters that route through the same NAT.
Baseline one normal week. In Cloud Billing reports, group by Service and SKU, then filter for Cloud NAT and network egress. Turn on VPC Flow Logs only for subnets you suspect, with a sample rate you can afford to store. If NAT logs are off, turn them on with a short retention window for the test, then decide whether to keep them.
How to do it
Start with the bill, not the console. In Cloud Billing, group by SKU and look at Cloud NAT gateway, Cloud NAT data processing, and the egress SKUs that match the same projects. That tells you whether the problem is idle gateways, high data volume, or both. Then use NAT logs or VPC Flow Logs to rank source instances, destinations and ports. A few chatty jobs often explain most of the traffic.
Move Google API traffic to private paths. Enable Private Google Access on subnets that host VMs and GKE nodes without external IPs. Use Private Service Connect endpoints for supported Google APIs and third party services that offer them. Point package managers and container builds at internal mirrors or Artifact Registry remote repositories so the same layer is not pulled from the internet on every build.
Tune the NAT itself. Turn on dynamic port allocation so busy VMs get more ports and small VMs do not hold a large block. Lower minimum ports per VM when you have many small instances. Keep NAT regional and close to the workloads. Do not add NAT IP addresses unless logs show port exhaustion or you need more throughput.
Check serverless and GKE egress settings. Cloud Run and Cloud Functions can send only private ranges through the VPC, which keeps internet bound traffic off your NAT unless you need a fixed egress address. GKE private nodes should use Private Google Access and Artifact Registry in the same region. Add egress firewall rules to block destinations the workload never needs.
- Baseline the bill by SKU. Group Cloud Billing reports by Service and SKU, then isolate Cloud NAT gateway, Cloud NAT data processing and egress. Save the view so you can compare the same filters later.
- Map NAT to workloads. List each Cloud Router and NAT with its region, IP count and logging setting. Match those to projects, GKE clusters and serverless jobs that use the same network.
- Enable Private Google Access. Turn on Private Google Access for subnets with VMs or nodes that have no external IP. Confirm that Google API calls work without adding NAT IP addresses.
- Use private endpoints and mirrors. Create Private Service Connect endpoints for supported services and point package managers at internal repositories. Use Artifact Registry remote repositories for container images that your builds pull often.
- Tune port allocation. Enable dynamic port allocation and set minimum ports per VM to match the instance sizes you run. Check NAT logs for port exhaustion before you add more NAT IP addresses.
- Fix serverless egress settings. Set Cloud Run and Cloud Functions VPC egress to private ranges only when they do not need a fixed public address. Remove unused serverless VPC connectors.
- Add egress firewall rules. Block destinations and ports that workloads never use. Keep the rules narrow and test each change from a VM without an external IP.
- Review logs and repeat. Use NAT logs and VPC Flow Logs to find the next top talker after each change. Repeat the billing comparison weekly until the NAT and egress lines stop moving.
How to check it worked
After a week, rerun the same billing view. Cloud NAT data processing should fall if you moved traffic to private paths. Gateway hours may not change if you kept the same number of NAT gateways, which is fine. Look for egress SKUs that moved rather than vanished.
Use NAT logs to check for allocation errors, port exhaustion and failed translations. Run gcloud compute routers nats describe NAT_NAME --router=ROUTER --region=REGION and confirm dynamic port allocation, minimum ports and IP count match your plan. Test package installs, container pulls and API calls from a VM without an external IP.
Use Connectivity Tests to confirm a VM can reach a private endpoint and a public endpoint as intended. Check application latency and error rates after the change. If a service needs a stable public IP, confirm it still leaves through the right NAT. Then set a budget alert on the projects you changed.
Mistakes to avoid
Do not turn off Cloud NAT to save money. VMs without external IPs will lose package updates, container pulls and public API access, and the failure may show up hours later. Remove NAT only after every workload has a private path or a deliberate public path.
Do not send Google API traffic through NAT when Private Google Access or Private Service Connect will do. Do not leave NAT logging at full translation volume forever if you only need errors. Do not assume dynamic port allocation reduces data processing charges, because it changes port allocation, not bytes.
Do not keep a NAT gateway running in a region with no steady workloads, because the gateway hours add up. Do not route all serverless egress through the VPC when only private ranges need it. Do not forget cross zone traffic between GKE services, which can cost more than the NAT line you started with.
If you want an outside read, Cloudverg's Cloud cost audit is $4,500/month for a two-week read-only review of up to three cloud accounts, including a data transfer and egress review. It is one option among a self review, your cloud partner or a consultant. Keep the changes small and measure each one.
Frequently asked questions
Why is Cloud NAT expensive on Google Cloud?
Cloud NAT has a gateway charge and a data processing charge. The data processing charge grows with bytes, and internet egress is billed separately. A single busy image pull or log shipper can dominate the line.
Does Private Google Access remove Cloud NAT costs?
It removes the need to send Google API traffic through NAT, so those bytes stop hitting NAT data processing. It does not remove NAT for general internet access. Use it with private endpoints and internal mirrors for the best result.
Should I use one Cloud NAT per region or per project?
Cloud NAT is regional and tied to a Cloud Router. Fewer gateways can cut gateway hours, but shared NAT creates a larger blast radius and port pressure. Match NAT to regions with real workloads and keep separate projects for teams that need independent change control.