GCP Network Security Best Practices: Secure VPC Hardening Guide
Securing a GCP network is not about flipping one switch. It is about combining multiple controls that each reduce a different kind of risk. This page walks through the full baseline: how to design your VPC correctly from the start, how to write firewall rules that do not leave holes, how to keep workloads off the public internet while still giving them the access they need, how to manage admin access safely, and how to get visibility into what is actually happening on your network. By the end you will have a clear picture of how these controls fit together and which ones matter most for your situation.
Simple explanation
Network security in GCP comes down to three goals: limit exposure, control access, and monitor traffic.
Limiting exposure means reducing the number of things an attacker can reach. Every VM with a public IP that accepts internet traffic is a potential target. The smaller your exposed surface, the fewer entry points exist.
Controlling access means making sure only the right traffic reaches the right resources. Firewall rules do this for network-level traffic. IAM and Identity-Aware Proxy do it for administrative access. VPC Service Controls do it for your managed data services.
Monitoring traffic means knowing what is happening so you can detect problems early. VPC Flow Logs give you a record of network flows. Without visibility, you can be breached and not know it for days.
No single control achieves all three goals. A good GCP network security posture layers these controls so that if one fails, the others still protect you.
Think of your GCP network like an office building. The VPC and subnets are the rooms and floors. Firewall rules are the key card readers on each door. Removing external IPs is like not having a public entrance at all for certain rooms. IAP is the security desk that checks your ID before letting you into the building. VPC Service Controls are the locked vault that even people inside the building cannot access without additional clearance. VPC Flow Logs are the CCTV cameras recording who goes where. Each layer is useful. None of them is enough on its own.
30-minute GCP network hardening checklist
If you are auditing an existing project or setting up a new one, work through this list first. These are the highest-value changes you can make.
- Audit firewall rules. List all ingress rules and look for anything sourcing from
0.0.0.0/0, especially on ports 22 (SSH), 3389 (RDP), and common database ports. Delete or narrow any rules that cannot be justified. - Remove external IPs. Check which VMs have external IP addresses and remove them from any VM that does not genuinely need inbound internet traffic. Use private IPs by default.
- Enable Private Google Access. Turn on Private Google Access on subnets so VMs without external IPs can still reach Google APIs (Cloud Storage, Pub/Sub, BigQuery) without going over the public internet.
- Configure Cloud NAT. Set up Cloud NAT for any subnet whose VMs need outbound internet access (package updates, external APIs) but do not have external IPs.
- Switch SSH to IAP. Stop allowing port 22 from
0.0.0.0/0. Create a firewall rule that only allows IAP’s IP range (35.235.240.0/20) to reach port 22, and usegcloud compute ssh —tunnel-through-iapfor all VM access. - Enable VPC Flow Logs. Turn on flow logs for subnets handling sensitive workloads so you have traffic visibility when you need to investigate an incident.
- Set the skipDefaultNetworkCreation org policy. Prevent future projects from starting with the insecure default VPC and its open firewall rules.
GCP’s default VPC comes pre-loaded with firewall rules that allow SSH, RDP, and ICMP from anywhere on the internet. This is designed for convenience when exploring GCP for the first time, not for real workloads. If you have projects using the default VPC, migrate to a custom VPC before adding production traffic.
How GCP network security works
GCP network security is built in layers. Each layer handles a different type of risk. Understanding how they fit together helps you decide which controls to apply and in what order.
Layer 1: VPC design and subnet structure
Everything starts with your VPC network. A custom mode VPC gives you full control over subnet design: you decide which regions get subnets, what IP ranges they use, and how they are segmented. The default VPC creates subnets automatically in every region, which is convenient but creates unnecessary exposure. In production, always use a custom VPC.
Good subnet design also helps contain failures. Separating your web tier, application tier, and data tier into different subnets means firewall rules can control what crosses tier boundaries. A compromised web server does not automatically have network access to your databases.
Layer 2: Firewall rules
Firewall rules control which traffic is allowed in and out of your VMs. GCP’s default is deny-all ingress and allow-all egress. You add explicit allow rules for what you actually need. The goal is least privilege: every rule should be as narrow as possible, scoped to specific source IPs, protocols, and target VMs.
Firewall rules can target specific VMs using network tags or service accounts. Service accounts are the more secure option because they are tied to IAM, not arbitrary labels that anyone with VM edit permissions can add.
Layer 3: Public IP exposure
Every VM with an external IP is reachable from the internet by default, subject only to firewall rules. Removing external IPs means even a misconfigured firewall rule creates no exposure — there is simply no route from the internet to the VM. This is one of the highest-value defences you can apply.
Private VMs still need to communicate outward. Private Google Access gives them a path to Google’s own APIs. Cloud NAT gives them a path to the rest of the internet. Neither creates inbound exposure.
Layer 4: Administrative access
Admin access (SSH, RDP) is often where the biggest risks live. The classic pattern of opening port 22 to the internet and relying on SSH keys creates unnecessary exposure. Identity-Aware Proxy (IAP) replaces this: every SSH connection is first authenticated by Google Identity, and the connection travels through Google’s infrastructure rather than directly to your VM. There is no open path to port 22 from the internet.
Layer 5: Data access controls
Firewall rules control network traffic between VMs, but they do not prevent a compromised workload from calling Google APIs and exfiltrating data. VPC Service Controls address this by creating a perimeter around your managed services (Cloud Storage, BigQuery, etc.). A compromised workload inside your network cannot copy data to a bucket in an attacker-controlled project outside the perimeter.
Layer 6: Visibility and monitoring
VPC Flow Logs record samples of network flows: source and destination IP, port, protocol, and bytes transferred. They are invaluable for security investigations, detecting unexpected lateral movement, and understanding what traffic actually flows through your environment. Without them, network security incidents are very hard to investigate after the fact.
Least-privilege firewall rules
The most common network security mistake in GCP is overly permissive firewall rules, especially ones that allow SSH or RDP from 0.0.0.0/0. These often get created during development to test something quickly and are then forgotten, staying open indefinitely.
Key practices for good firewall hygiene:
- Restrict source ranges: never use
0.0.0.0/0for sensitive ports. Restrict to your office IP range, VPN exit nodes, or another specific subnet. If the source is unknown or variable, use IAP instead. - Use service accounts as targets, not network tags: network tags can be added to a VM by anyone with the Compute Instance Admin role, which lets them gain whatever access the tag unlocks without touching IAM. Service account-based rules tie access to the VM’s identity, which requires explicit IAM permission to change.
- Name and describe your rules: a rule called
allow-tcp-443with no description becomes unmanageable over time. Use descriptive names likeallow-web-lb-to-app-443and add descriptions explaining what each rule is for. - Understand priority order: GCP evaluates rules from lowest number (highest priority) to highest number. A deny rule at priority 900 overrides an allow rule at priority 1000. Know the ordering before adding rules to an existing VPC.
- Audit and delete unused rules: run regular audits and remove any rule that cannot be explained. Target especially any rule created for debugging that opens broad access.
# List all firewall rules in your project with key details
gcloud compute firewall-rules list \
--format='table(name,direction,priority,sourceRanges,targetTags,targetServiceAccounts,allowed)'
# Find overly permissive ingress rules with source 0.0.0.0/0
gcloud compute firewall-rules list \
--filter='sourceRanges:0.0.0.0/0 AND direction:INGRESS' \
--format='table(name,allowed,targetTags,targetServiceAccounts)'
# Delete a firewall rule that is no longer needed
gcloud compute firewall-rules delete old-debug-ruleRemove external IP addresses from VMs
Every VM with an external IP is directly addressable from the internet. Even with strict firewall rules today, external IPs increase risk because any future misconfiguration immediately creates exposure. The GCP default is to assign an ephemeral external IP to new VMs unless you explicitly opt out. This default is wrong for most production workloads.
Running VMs with internal IPs only means there is no route from the internet to them, regardless of firewall state. This is a strong defence because it removes the exposure entirely rather than relying on rules staying correct forever.
Private VMs still need to communicate outward. There are two distinct paths, and they are not substitutes for each other:
- For Google APIs and services (Cloud Storage, Pub/Sub, BigQuery, etc.): enable Private Google Access on the subnet. Traffic to Google APIs stays on Google’s internal network and never touches the public internet.
- For the public internet (OS updates, third-party APIs, package downloads): configure Cloud NAT. Cloud NAT gives VMs outbound-only internet access through shared NAT IP addresses. No inbound connections from the internet are possible through it.
# Create a VM with no external IP
gcloud compute instances create private-vm \
--zone=europe-west2-a \
--machine-type=e2-medium \
--no-address
# Enable Private Google Access on a subnet so private VMs can reach Google APIs
gcloud compute networks subnets update my-subnet \
--region=europe-west2 \
--enable-private-ip-google-access
# Verify a VM has no external IP (output should be empty)
gcloud compute instances describe private-vm \
--zone=europe-west2-a \
--format='value(networkInterfaces[0].accessConfigs)'For SSH access to VMs without external IPs, use Identity-Aware Proxy (IAP) for TCP tunnelling. IAP verifies IAM permissions before forwarding the connection — no bastion host or VPN required. Grant the roles/iap.tunnelResourceAccessor role to authorised users and use gcloud compute ssh —tunnel-through-iap.
SSH access via IAP
The classic approach to SSH — open port 22 in a firewall rule to the internet, distribute SSH keys — has a significant problem: every VM with port 22 open to 0.0.0.0/0 is being scanned by automated tools constantly. Even with strong keys, it is unnecessary exposure that IAP eliminates entirely.
Any VM with port 22 open to 0.0.0.0/0 is receiving automated attack attempts right now. Internet-wide scanners probe every public IP continuously looking for open SSH ports. This is not hypothetical. IAP removes this exposure completely — your VM does not need a public IP, and port 22 is never open to the internet.
Identity-Aware Proxy TCP tunnelling works differently. The engineer runs gcloud compute ssh locally. Google’s infrastructure authenticates them against IAM, and only then forwards the TCP connection to the VM. The VM does not need port 22 open to the internet — the firewall rule only allows traffic from IAP’s fixed IP range (35.235.240.0/20). The VM does not even need an external IP.
# Create a firewall rule allowing IAP (and only IAP) to forward SSH
# Target specific VMs by service account for least privilege
gcloud compute firewall-rules create allow-iap-ssh \
--network=my-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20 \
--target-service-accounts=my-vm-sa@my-project.iam.gserviceaccount.com
# SSH to a private VM through IAP — no external IP required
gcloud compute ssh my-vm \
--zone=europe-west2-a \
--tunnel-through-iap
# Grant a user the IAP tunnel access role
gcloud projects add-iam-policy-binding my-project \
--member='user:engineer@example.com' \
--role='roles/iap.tunnelResourceAccessor'Every IAP connection is logged in Cloud Audit Logs, giving you a record of who connected to which VM and when. This is far easier to audit than tracking SSH key distribution across a growing team. When someone leaves the organisation, you revoke their IAM role and they lose access instantly — no key rotation required.
VPC Service Controls
VPC Service Controls (VPC-SC) solve a different problem from firewall rules. Firewall rules control network traffic between VMs. VPC Service Controls control access to GCP managed services — Cloud Storage, BigQuery, Pub/Sub, and others. Their purpose is to prevent data exfiltration: stopping a compromised workload or stolen credential from copying sensitive data to an attacker-controlled project.
Imagine your building has a secure document room. You have key card access to enter the building (firewall rules), but the document room has an additional rule: you can only take documents if you are inside the building and on an approved list. Even if someone steals your key card and swipes it from outside, they cannot take documents from that room. That is what VPC Service Controls do for your Cloud Storage buckets and BigQuery datasets.
A VPC-SC perimeter defines which projects are inside the boundary and which GCP APIs are restricted within it. Once a service is inside the perimeter, API requests to that service are only allowed from within the perimeter or from explicitly approved access levels (a trusted IP range, a trusted identity, or a device meeting a specific posture).
A service perimeter specifies:
- Protected services: which GCP APIs are restricted (Cloud Storage, BigQuery, Pub/Sub, etc.)
- Resources inside the perimeter: which GCP projects are covered
- Access levels: conditions allowing access from outside (specific IP ranges, trusted identities, device posture requirements)
# Enable the Access Context Manager API (required for VPC Service Controls)
gcloud services enable accesscontextmanager.googleapis.com
# Create an access policy — one per organisation, check if one already exists first
gcloud access-context-manager policies create \
--organisation=123456789 \
--title="My Security Policy"
# Service perimeters are complex — use Terraform so the configuration is version-controlled
# Always test in dry-run mode before switching to enforcedEnforcing VPC Service Controls incorrectly breaks things silently. Common casualties include Cloud Build pipelines, Terraform state operations, and monitoring alert policies — all of which make API calls that may be outside your perimeter. Dry-run mode logs what would be blocked without actually blocking anything. Spend time in dry-run, fix all issues, then switch to enforced.
VPC Flow Logs
VPC Flow Logs record samples of network flows through your VM interfaces: source and destination IP, port, protocol, and bytes transferred. They are not a full packet capture, but they give you enough to answer most security questions. Where is this VM sending traffic? What connected to this VM at 3am? Is there unexpected traffic crossing between subnets?
Flow logs are enabled per subnet and sampled at a configurable rate. They write to Cloud Logging and can be exported to BigQuery for longer retention and deeper analysis. They have a cost, so be selective — enable them on subnets handling sensitive data, internet-facing workloads, or any subnet where you would want visibility during an incident.
# Enable VPC Flow Logs on a subnet with 50% sampling rate
gcloud compute networks subnets update my-subnet \
--region=europe-west2 \
--enable-flow-logs \
--logging-flow-sampling=0.5 \
--logging-aggregation-interval=interval-5-sec
# Export flow logs to BigQuery for analysis and longer retention
gcloud logging sinks create vpc-flows-to-bq \
bigquery.googleapis.com/projects/my-project/datasets/network_logs \
--log-filter='resource.type="gce_subnetwork"'Cloud Logging retains logs for 30 days by default. Security investigations often need to go back further. Export flow logs to BigQuery using a log sink if your environment handles sensitive data — it gives you a much longer window and lets you run SQL queries against network traffic patterns across weeks or months.
The most important thing about flow logs: enable them before you need them. You cannot retroactively capture traffic from an incident that already happened.
Organisation policies for network security
Individual project owners can make insecure choices: leaving external IPs on VMs, using the default VPC, skipping flow logs. Organisation policies let you prevent these choices at the organisation or folder level, regardless of what individual project owners do. They are the right tool for enforcing a security baseline across many teams and projects.
The most useful policies for network security:
constraints/compute.vmExternalIpAccess: restrict which VMs can have external IPs, or deny all external IPs across the organisationconstraints/compute.skipDefaultNetworkCreation: prevent the default VPC from being created when new projects are createdconstraints/compute.requireShieldedVm: require all VMs to use Shielded VM features (Secure Boot, vTPM, integrity monitoring)constraints/compute.restrictCloudNATUsage: control which projects can create Cloud NAT gateways, useful when all internet access should route through a central inspection point
# Prevent the default network from being created in new projects
gcloud org-policies set-policy --organisation=123456789 - <<EOF
name: organisations/123456789/policies/compute.skipDefaultNetworkCreation
spec:
rules:
- enforce: true
EOF
# Deny all external IPs across the organisation
gcloud org-policies set-policy --organisation=123456789 - <<EOF
name: organisations/123456789/policies/compute.vmExternalIpAccess
spec:
rules:
- denyAll: true
EOFSegmentation and reducing blast radius
Strong perimeter controls are important, but internal segmentation limits how much damage a single compromised workload can do. If your web tier, application tier, and data tier all share a subnet with open internal traffic, a compromised web server has direct network access to your databases. With proper segmentation and firewall rules between tiers, the blast radius shrinks significantly.
Practical segmentation in GCP:
- Put different workload tiers in different subnets and write explicit firewall rules for cross-subnet traffic. Only allow what each tier actually needs to call.
- For organisations with multiple teams, use Shared VPC to centralise network control. Teams get their own projects but cannot create ad-hoc networks or firewall rules that bypass central controls.
- Keep production, staging, and development in separate projects. Connect them when needed with Cloud VPN or Cloud Interconnect — do not merge them into one flat network where dev credentials can reach production resources.
- For GKE workloads, use private clusters with no public API endpoint and restrict master authorised networks to known IP ranges.
When to use these practices
Not every control applies equally to every situation. Here is how to think about which ones matter most for your context.
New production project
Apply the full baseline from day one: custom VPC, no external IPs on VMs, Private Google Access on subnets, Cloud NAT for outbound internet, IAP for SSH, VPC Flow Logs on key subnets, and the org policy to skip default network creation. This setup takes under an hour and removes the most common risk patterns before they become habits.
Internal-only services
If your services only need to be reachable from within your organisation (internal tools, admin dashboards, reporting systems), there is no reason for any external IP or public-facing load balancer. Use an internal load balancer, run VMs with private IPs only, and access everything through IAP or a corporate VPN or Cloud Interconnect connection.
Regulated or sensitive workloads
For environments handling PCI, HIPAA, or other regulated data, add VPC Service Controls on top of the standard baseline. Also consider enabling Cloud Audit Logs on all APIs, exporting flow logs to a long-retention BigQuery dataset, and using org policies to lock down project-level configuration changes.
Teams migrating from default VPC habits
If you inherited a project using the default VPC, the migration path is: create a custom VPC, rewrite your firewall rules with proper scoping, move workloads over (recreating VMs without external IPs), then delete the default VPC. It is disruptive but worth doing before the environment grows larger. Set the compute.skipDefaultNetworkCreation org policy to prevent the pattern from recurring in new projects.
Environments where engineers SSH directly over the internet
This is one of the highest-priority changes you can make. Every VM reachable on port 22 from 0.0.0.0/0 is being scanned constantly. Switch to IAP tunnelling. The firewall change is simple: remove the broad SSH rule and add one allowing only 35.235.240.0/20. The engineer experience barely changes — they run the same gcloud compute ssh command with —tunnel-through-iap added.
Shared multi-team environments
When multiple teams share infrastructure, individual engineers may have enough permissions to add permissive firewall rules or attach external IPs to VMs. Use org policies to enforce guardrails at the folder level, and use Shared VPC so network-level changes require approval from a central network team rather than being self-service.
Common mistakes
Exposing SSH or RDP to 0.0.0.0/0. These are the most scanned port ranges on the internet. Any VM with port 22 open to the world receives automated attack attempts constantly. Fix: switch to IAP tunnelling and restrict the SSH firewall rule to IAP’s IP range (
35.235.240.0/20) only. This eliminates direct internet exposure for admin access entirely.Leaving external IPs on VMs by default. GCP assigns ephemeral external IPs to new VMs unless you explicitly opt out. Many teams never check this, resulting in internal workloads reachable from the internet whenever a firewall rule is misconfigured. Fix: use
—no-addresswhen creating VMs, and set thecompute.vmExternalIpAccessorg policy to prevent external IPs at the organisation level.Relying on network tags without understanding the risks. If your firewall rules target network tags, any user with the Compute Instance Admin role can add that tag to a VM and gain whatever access the tag grants — without touching IAM at all. Fix: use service accounts as firewall targets for production rules. The network tags guide covers the full risk model.
Not enabling VPC Flow Logs on important subnets. Flow logs are often the first place to look during an incident: unexpected outbound connections, lateral movement between VMs, traffic spikes to unusual destinations. Teams skip them to avoid the cost, then have no visibility when something goes wrong. Fix: enable flow logs on subnets handling sensitive data or internet-facing workloads, before you need them.
Assuming Cloud NAT protects inbound access. Cloud NAT provides outbound-only internet access for VMs without external IPs. It does nothing to protect VMs that already have external IPs. If a VM has an external IP and an open firewall rule, Cloud NAT is irrelevant to that exposure. Fix: understand that removing external IPs and configuring Cloud NAT are separate steps that must both be done.
Using the default VPC in production. The default VPC comes with firewall rules that allow SSH, RDP, and ICMP from anywhere on the internet. It also creates subnets in every region, including ones you may never use. Fix: use a custom mode VPC for production and set the org policy to prevent the default VPC from appearing in new projects.
Enforcing VPC Service Controls without dry-run testing first. VPC-SC is powerful but easy to misconfigure. Common mistakes include missing CI/CD service accounts (builds break), missing monitoring service accounts (alerting breaks), and missing cross-project dependencies that were not mapped in advance. Fix: always start in dry-run mode, review what would be blocked, fix issues, and only switch to enforced after thorough testing.
Confusing Private Google Access with general outbound internet access. Private Google Access only covers access to Google-owned APIs and services. It does not let your VM download packages from apt, call a third-party REST API, or reach the public internet in any other way. For those use cases, you need Cloud NAT in addition. Fix: enable both when private VMs need both types of outbound access.
Choosing the right control
Several GCP controls overlap in purpose and are easy to confuse. Here is how to tell them apart.
Private Google Access vs Cloud NAT
Private Google Access does not give your VM internet access. It only covers Google’s own services (Cloud Storage, BigQuery, Pub/Sub, etc.). If you enable Private Google Access but not Cloud NAT, your VM still cannot download a package from apt, reach a GitHub repository, or call any non-Google API. These are completely separate controls.
Private Google Access lets VMs without external IPs reach Google-owned APIs and services without that traffic ever leaving Google’s network. It is enabled per subnet with one flag and adds no meaningful cost beyond the API calls themselves. It does nothing for non-Google destinations.
Cloud NAT lets VMs without external IPs make outbound connections to anything on the public internet: package repositories, third-party APIs, GitHub, npm registries. It translates the VM’s private IP to a shared pool of NAT IP addresses. No inbound connections from the internet can reach your VMs through it.
In practice you often need both: Private Google Access for Google API calls, Cloud NAT for everything else. They are not substitutes.
IAP vs exposing SSH publicly
Traditional SSH access means opening port 22 in a firewall rule to the internet (or a wide IP range) and relying on SSH keys. IAP TCP tunnelling replaces this model: the SSH connection routes through Google’s infrastructure, with IAM authentication as the gate.
With IAP, the VM does not need a public IP. The firewall rule restricts to IAP’s IP range, not the open internet. Access is controlled by IAM roles instead of SSH key distribution. Every connection is logged in Cloud Audit Logs. No VPN or bastion host is required.
There is no meaningful reason to expose SSH directly to the internet when IAP is available. IAP is strictly safer, easier to audit, and easier to manage at scale — and the developer workflow is nearly identical.
Firewall rules vs VPC Service Controls
Firewall rules control network traffic between VMs (and between VMs and the internet). They answer: can this IP address reach this VM on this port? They say nothing about what an already-connected workload does next — a VM that can reach your network can still call Google APIs and exfiltrate data from Cloud Storage.
VPC Service Controls operate at the API level. They answer: can this identity, calling from this network location, access this GCP managed service? They stop a compromised workload from exfiltrating data through managed services, even if the workload is legitimately on your network.
Use firewall rules for all environments. Add VPC Service Controls on top for environments where data exfiltration from managed services is a real threat — typically anywhere handling sensitive or regulated data.
Summary
- GCP network security combines multiple layers: VPC design, firewall rules, private IPs, IAP, VPC Service Controls, and monitoring. No single control is sufficient on its own.
- Write least-privilege firewall rules: restrict source ranges, prefer service accounts over network tags, and audit and delete unused rules regularly.
- Remove external IPs from VMs that do not need direct internet exposure. Enable Private Google Access for Google API calls and Cloud NAT for outbound internet access — they serve different purposes and you often need both.
- Use IAP TCP tunnelling for SSH. It removes the need to expose port 22 to the internet entirely, and every connection is logged in Cloud Audit Logs.
- Enable VPC Flow Logs on sensitive subnets before you need them. You cannot retroactively capture traffic from an incident that already occurred.
- Enforce organisation policies (skipDefaultNetworkCreation, vmExternalIpAccess) to prevent insecure defaults from appearing in new projects.
- Add VPC Service Controls for regulated or sensitive environments where data exfiltration protection is required. Always start in dry-run mode and test before enforcing.
- Use subnet segmentation and Shared VPC to limit blast radius and centralise network control in multi-team environments.
Frequently asked questions
What is the safest default network setup in GCP?
Start with a custom mode VPC (not the default VPC), no external IPs on your VMs, least-privilege firewall rules scoped to specific source ranges or service accounts, Private Google Access enabled on subnets, and Cloud NAT for any outbound internet traffic. Use IAP for SSH instead of opening port 22 to the internet. This baseline is appropriate for most new production projects before you layer on VPC Service Controls for sensitive data.
Should I use network tags or service accounts in firewall rules?
Service accounts are more secure. Network tags are arbitrary strings that any user with permission to modify a VM can add or remove, potentially granting themselves access through firewall rules. Service account-based rules tie access to the identity of the workload, which is controlled by IAM and cannot be changed without explicit permission. Use service accounts in firewall rules for production workloads wherever possible.
Do private VMs still need Cloud NAT or Private Google Access?
They are different things. Private Google Access lets VMs without external IPs reach Google APIs (Cloud Storage, Pub/Sub, BigQuery, etc.) over Google's internal network — no internet involved. Cloud NAT lets VMs without external IPs make outbound connections to the public internet (to download packages or call external APIs). You often need both: Private Google Access for Google services, and Cloud NAT for everything else. Neither one allows inbound connections from the internet to your VMs.
When do I need VPC Service Controls?
VPC Service Controls are most valuable when you handle sensitive or regulated data in GCP managed services like Cloud Storage or BigQuery. They create a perimeter that prevents data from being copied to projects outside it — protection against insider threats and compromised credentials. For a simple web app or development environment they are usually not needed. They require an organisation resource and are complex to configure — start in dry-run mode before enforcing.
How do I stop new projects from creating insecure default networking?
Set the compute.skipDefaultNetworkCreation organisation policy constraint to enforced=true at the organisation or folder level. This prevents GCP from creating the default VPC (with its permissive firewall rules) when new projects are created. You should also consider setting compute.vmExternalIpAccess to deny all external IPs by default, so developers cannot accidentally attach public IPs to VMs.