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 with | enable-oslogin=TRUE in project or instance metadata | default when OS Login is off |
| Who may log in | Holders of roles/compute.osLogin (no sudo) or roles/compute.osAdminLogin (sudo) | Anyone whose public key is in metadata |
| Account lifecycle | POSIX account created automatically from the Google identity; access ends when the IAM role is removed | Keys must be added and removed by hand |
| Extras | Optional 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.