Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ShubhamRasal/4b6e76bdc21d8f564efd82c1398093b1 to your computer and use it in GitHub Desktop.

Select an option

Save ShubhamRasal/4b6e76bdc21d8f564efd82c1398093b1 to your computer and use it in GitHub Desktop.
SSH into GCP VMs via IAP using standard SSH config — ProxyCommand setup and the username trap

SSH into GCP VMs via IAP Using Standard SSH Config

If your GCP VMs don't have external IPs (or you use IAP for security), gcloud compute ssh --tunnel-through-iap works — but it's verbose. You can't use it with scp, rsync, Ansible, or VSCode Remote-SSH easily.

This guide shows how to set up ~/.ssh/config so you can just run:

ssh my-vm

and it tunnels through IAP automatically.

Why not gcloud compute config-ssh? It doesn't support IAP. It generates config with external IPs, which won't work for VMs behind IAP with no public IP.

SSH Config with IAP ProxyCommand

Add this to ~/.ssh/config:

Host my-vm
    ProxyCommand gcloud compute start-iap-tunnel VM_NAME %p --listen-on-stdin --zone=ZONE --project=PROJECT_ID
    IdentityFile ~/.ssh/google_compute_engine
    User USERNAME
    UserKnownHostsFile ~/.ssh/google_compute_known_hosts
    IdentitiesOnly yes
    CheckHostIP no

The key line is ProxyCommand — it uses gcloud compute start-iap-tunnel with --listen-on-stdin to pipe the SSH connection through IAP instead of connecting to an external IP.

Replace:

  • my-vm — your alias (whatever you want after ssh)
  • VM_NAME — GCP instance name
  • ZONE — e.g., us-east1-b
  • PROJECT_ID — e.g., my-project-prod
  • USERNAMEread the next section carefully

The Username Trap (The Part That Will Waste Your Time)

You set everything up, run ssh my-vm, and get:

Permission denied (publickey).

The key is correct. The tunnel works. But the username is wrong.

GCP has two SSH authentication modes, and each uses a different username format:

Mode 1: Traditional SSH Keys (metadata-based)

The VM has a ~/.ssh/authorized_keys file. Your username is whatever gcloud compute ssh created on the VM — usually your local macOS/Linux username.

User shubhamrasal

Mode 2: OS Login

Google manages keys centrally. Your username is derived from your Google account email — @ and . become _.

# shubham@projectdiscovery.io becomes:
User shubham_projectdiscovery_io

How to Find Your Username

Quick way — let gcloud tell you:

gcloud compute ssh VM_NAME --zone=ZONE --project=PROJECT_ID --tunnel-through-iap --dry-run

Look for username@ in the output. That's your User.

Or check which mode is active:

# Project-level setting
gcloud compute project-info describe --format='value(commonInstanceMetadata.items.enable-oslogin)'

# Instance-level override
gcloud compute instances describe VM_NAME --zone=ZONE --format='value(metadata.items.enable-oslogin)'
  • TRUE → OS Login. Get username: gcloud compute os-login describe-profile (look for username field)
  • Empty or FALSE → Traditional. SSH in once with gcloud, run whoami

Identity File

gcloud compute ssh auto-generates a key pair at ~/.ssh/google_compute_engine on first use. If this file doesn't exist:

# This creates the key and registers it
gcloud compute ssh VM_NAME --zone=ZONE --project=PROJECT_ID --tunnel-through-iap

For OS Login, ensure the key is registered:

gcloud compute os-login ssh-keys add --key-file=~/.ssh/google_compute_engine.pub --project=PROJECT_ID

Debugging Permission denied (publickey)

ssh -v my-vm 2>&1 | grep -E "Offering|identity|Authentication"

You'll see something like:

debug1: Offering public key: ~/.ssh/google_compute_engine RSA SHA256:xxxx explicit
debug1: Authentications that can continue: publickey

If the key is offered but rejected:

  1. Wrong username (most common) — see the username section above
  2. Key not registered — for OS Login: gcloud compute os-login describe-profile to verify. For traditional: check ~/.ssh/authorized_keys on the VM
  3. Wrong key file — compare fingerprints:
    # Local key fingerprint
    ssh-keygen -lf ~/.ssh/google_compute_engine.pub
    
    # What's registered in OS Login
    gcloud compute os-login describe-profile

Complete Example

# Production VM — traditional SSH keys, behind IAP
Host prod-server
    ProxyCommand gcloud compute start-iap-tunnel prod-vm %p --listen-on-stdin --zone=us-east1-b --project=my-company-prod
    IdentityFile ~/.ssh/google_compute_engine
    User shubhamrasal
    UserKnownHostsFile ~/.ssh/google_compute_known_hosts
    IdentitiesOnly yes
    CheckHostIP no

# Dev VM — OS Login enabled, behind IAP
Host dev-server
    ProxyCommand gcloud compute start-iap-tunnel dev-vm %p --listen-on-stdin --zone=us-central1-a --project=my-company-dev
    IdentityFile ~/.ssh/google_compute_engine
    User shubham_company_io
    UserKnownHostsFile ~/.ssh/google_compute_known_hosts
    IdentitiesOnly yes
    CheckHostIP no

Notice: prod-server uses plain username (traditional mode), dev-server uses email-derived username (OS Login). They can coexist.

Now You Can Use Standard SSH Tools

# Direct SSH
ssh prod-server

# SCP
scp ./deploy.sh prod-server:/tmp/

# Rsync
rsync -avz ./app/ prod-server:/opt/app/

# VSCode Remote-SSH — just pick "prod-server" from the host list

# Ansible inventory
# [production]
# prod-server

Prerequisites

  • gcloud CLI installed and authenticated (gcloud auth login)
  • IAP TCP forwarding enabled (docs)
  • roles/iap.tunnelResourceAccessor IAM role on the VM or project
  • ~/.ssh/google_compute_engine key pair (auto-created on first gcloud compute ssh)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment