Use IAP TCP Forwarding to Reach Compute Engine VMs Without Public SSH Ports
Tunnel to a Compute Engine VM's internal IP with Google Cloud IAP, control access with IAM, and audit sessions in Cloud Logging.
29 Jul 2026, 21:13 UTC

Problem and takeaway
Opening port 22 or 3389 to the internet exposes every Compute Engine VM to brute-force and credential-stuffing attempts. Bastion hosts reduce that exposure, but they add instances to patch, monitor, and pay for. Google Cloud Identity-Aware Proxy (IAP) TCP forwarding lets you reach a VM's internal IP through an authenticated TLS tunnel without assigning the VM a public IP or opening SSH/RDP to the public internet.
The practical result is that you can administer Linux and Windows instances with gcloud compute start-iap-tunnel, gate entry with Identity and Access Management (IAM) roles, and review every tunnel request in Cloud Audit Logs.
Prerequisites
- Google Cloud CLI (gcloud), current stable release, installed and authenticated on your local workstation.
- A running Compute Engine VM in the target project.
- IAP enabled for the project or the specific VM.
- An IAM binding granting
roles/iap.tunnelResourceAccessorto the user or group that needs tunnel access. - A Virtual Private Cloud (VPC) firewall rule allowing ingress from Google's IAP proxy ranges to the VM on the target port (22 for SSH, 3389 for RDP).
- If the VM has no external IP, an outbound path to Google APIs through Cloud NAT or Private Google Access. Confirm this in your environment; tunnel signaling behavior depends on VPC configuration.
Grant IAP tunnel access
Run this command from a terminal where the gcloud CLI is authenticated. You need resourcemanager.projects.setIamPolicy on the project or compute.instances.setIamPolicy on the VM.
gcloud compute instances add-iam-policy-binding INSTANCE_NAME --member=user:USER_EMAIL --role=roles/iap.tunnelResourceAccessor --zone=ZONE
Replace INSTANCE_NAME, USER_EMAIL, and ZONE with your values. Avoid project-level bindings unless you intend to grant tunnel access to every instance in the project.
Check the firewall rule
Before opening a tunnel, confirm that a VPC firewall rule permits ingress from IAP proxy addresses to the instance network on tcp:22 or tcp:3389. Without this rule, the tunnel may negotiate but the VM drops the forwarded connection.
gcloud compute firewall-rules list --filter=name:iap-ssh
Adjust the filter to match your firewall naming convention. If no rule exists, create one that allows the IAP proxy ranges to reach the VM's subnet or network tags on the required port.
Start the tunnel and connect
Run the tunnel command from your local workstation:
gcloud compute start-iap-tunnel INSTANCE_NAME 22 --zone=ZONE
The command establishes a TLS-encrypted tunnel to the VM's internal IP and prints the local port it is listening on. Leave this command running.
In a second terminal, connect to the forwarded port:
ssh -p LOCAL_PORT USER_NAME@localhost
Replace LOCAL_PORT with the port printed by the tunnel command. For Windows instances, point an RDP client at localhost:LOCAL_PORT instead.
Expected checks
- The tunnel command stays active and does not exit immediately.
- SSH or RDP to localhost reaches the VM and prompts for OS-level credentials. IAP authenticates your Google identity; the operating system still requires a valid SSH key or Windows password.
- Cloud Logging contains
cloudaudit.googleapis.com/system_evententries for the tunnel request, showing which identity accessed which instance and when.
Limitations
- IAP does not replace OS authentication. Valid SSH keys or Windows credentials are still required after the IAP layer approves the connection.
- VMs without external IPs need Cloud NAT or Private Google Access for outbound tunnel signaling. If this path is missing, the tunnel fails to establish.
- Missing IAM bindings or firewall rules that block IAP ranges cause connection failures. With public SSH disabled, there is no direct SSH fallback unless you re-enable public access or configure another path.
Rollback and recovery
Because granting IAM and changing firewall rules changes state, reverse them when the access is no longer needed:
gcloud compute instances remove-iam-policy-binding INSTANCE_NAME --member=user:USER_EMAIL --role=roles/iap.tunnelResourceAccessor --zone=ZONE
Delete any temporary firewall rule created only for this test. Re-enable public SSH or RDP only as a last resort, and restrict it to known administrative IP ranges.
Practical verification
After setup, run gcloud compute start-iap-tunnel INSTANCE_NAME 22 --zone=ZONE and confirm the local listener appears. Then query Cloud Logging for audit entries matching the VM and your identity. If the tunnel does not establish, check the IAM binding first, then the VPC firewall rule, then the VM's outbound path to Google APIs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.