SSH to a Linux VM on Google Cloud via IAP

gcloud compute ssh --tunnel-through-iap gives you a shell on a Linux VM that has no external IP, with the connection wrapped inside HTTPS to Identity-Aware Proxy and access gated by IAM rather than a firewall opening. This page covers the one-off setup, the daily command, and how to make plain ssh, scp and VS Code use the same tunnel.

1. One-off setup

Firewall rule allowing IAP's range to port 22:

gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
  --direction=INGRESS --action=allow --rules=tcp:22 \
  --source-ranges=35.235.240.0/20

IAM. The user needs roles/iap.tunnelResourceAccessor on the project or the instance. Google's TCP-forwarding guide also lists roles/compute.instanceAdmin.v1, because gcloud compute ssh reads instance details (compute.instances.get, compute.instances.list) and, without OS Login, pushes your public key into instance metadata.

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member=user:[email protected] --role=roles/iap.tunnelResourceAccessor

2. The daily command

gcloud compute ssh INSTANCE_NAME --tunnel-through-iap --project PROJECT_ID --zone ZONE

If the VM has no external IP, gcloud uses IAP automatically; --tunnel-through-iap makes it explicit (and forces the tunnel on VMs that do have one). Unlike the RDP flow there is no local listening port — gcloud "wraps the SSH connection inside HTTPS and forwards it to the remote instance".

3. Who logs in: OS Login vs metadata keys

Two ways to map your Google identity to a Linux account:

OS Login (recommended)Metadata SSH keys
Enable withenable-oslogin=TRUE in project or instance metadatadefault when OS Login is off
Who may log inHolders of roles/compute.osLogin (no sudo) or roles/compute.osAdminLogin (sudo)Anyone whose public key is in metadata
Account lifecyclePOSIX account created automatically from the Google identity; access ends when the IAM role is removedKeys must be added and removed by hand
ExtrasOptional 2-step verification, SSH certificates, audit logging

Enable OS Login project-wide:

gcloud compute project-info add-metadata --metadata enable-oslogin=TRUE
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member=user:[email protected] --role=roles/compute.osLogin

Once OS Login is on, metadata-based keys are ignored, so pick one model per project.

4. Plain ssh, scp and rsync through IAP

Ask gcloud for the exact command it would run:

gcloud compute ssh INSTANCE_NAME --tunnel-through-iap --zone ZONE --dry-run

It prints an ssh invocation whose -o ProxyCommand=... uses gcloud compute start-iap-tunnel INSTANCE_NAME 22 --listen-on-stdin .... Put that into ~/.ssh/config so every OpenSSH tool works unchanged:

Host myvm
  HostName INSTANCE_NAME
  User YOUR_LINUX_USER
  ProxyCommand gcloud compute start-iap-tunnel %h %p --listen-on-stdin --project=PROJECT_ID --zone=ZONE

Then ssh myvm, scp file myvm:/tmp/, rsync -e ssh … all tunnel through IAP. On Windows with PuTTY, set the proxy command to gcloud.cmd compute start-iap-tunnel %host %port --listen-on-stdin --project PROJECT_ID --zone ZONE.

5. VS Code Remote-SSH

Because Remote-SSH reads ~/.ssh/config, the Host myvm block above is all it needs: Remote-SSH: Connect to Host… → myvm. The extension installs its server over the tunnel.

6. Keeping the session alive

IAP disconnects idle sessions after one hour. Add ServerAliveInterval 60 to the host block to keep a quiet terminal from going idle; for long-running jobs use tmux on the VM. If throughput matters, install NumPy for gcloud's Python:

$(gcloud info --format="value(basic.python_location)") -m pip install numpy
export CLOUDSDK_PYTHON_SITEPACKAGES=1

Common questions

"Permission denied (publickey)" after the tunnel opens

The tunnel worked; the OS rejected you. With OS Login on, you need roles/compute.osLogin or osAdminLogin; with it off, your key must be in metadata (gcloud compute ssh adds it if you have compute.instanceAdmin.v1).

How do I get sudo with OS Login?

Grant roles/compute.osAdminLogin instead of roles/compute.osLogin.

Can I forward a port over the SSH session?

Yes — normal -L/-R flags work: ssh -L 8080:localhost:8080 myvm. For a non-SSH port you can also tunnel it directly with start-iap-tunnel.

Does the VM see my IP?

No — connections arrive from IAP's 35.235.240.0/20 range. who/last show that address, while OS Login audit logs record your Google identity.

Sources