GCP Compute Engine IAP Tunnel Connection Failure from Local VS Code / gcloud compute start-iap-tunnel

I am unable to establish an IAP-secured SSH connection to my Google Compute Engine VM ( my-vm , Project ID:(PII Removed by Staff) , Zone: europe-west3-a ) from my local machine (macOS). This issue persists both when attempting to connect via VS Code Remote - SSH and when directly executing the gcloud compute start-iap-tunnel command.

I am a new bee to cloud and tried Cloud Assistant AI, and debugged with it for two days. Now I asked it to generate a summary for me so I can post on the forum. I hope I can connect my VM via SSH from my VS Code

While gcloud compute ssh my-vm --project=(PII Removed by Staff) --zone=europe-west3-a works successfully (connecting via key-based authentication, without a password), the gcloud compute start-iap-tunnel command (which is used by ProxyCommand in ~/.ssh/config for VS Code) fails to complete the tunnel setup.

Observed Behavior and Error Messages:

  1. Direct gcloud compute start-iap-tunnel command execution ( gcloud compute start-iap-tunnel my-vm 22 --project=(PII Removed by Staff) --zone=europe-west3-a --verbosity=debug ):

    • The command successfully initiates the websocket connection to tunnel.cloudproxy.app .

    • It receives data ( RECV opcode [2] ) from the IAP service, indicating an initial handshake.

    • However, immediately after receiving data, it attempts to close the websocket, resulting in an OSError: [Errno 9] Bad file descriptor and websocket._exceptions.WebSocketConnectionClosedException .

    • Despite these errors, it eventually outputs Listening on port [XXXX].(where XXXX is a local port), but the underlying tunnel is already broken.

    Example Output (Condensed):

    DEBUG: Running [gcloud.compute.start-iap-tunnel] with arguments: […]
    
    Picking local unused port [60606].
    
    Testing if tunnel connection works.
    
    DEBUG: [-1] user-agent […] python/3.10.9 […]
    
    DEBUG: credentials type for _GetAccessTokenCallback is […].
    
    DEBUG: [-1] Using new websocket library
    
    INFO: [-1] Connecting with URL [‘wss://tunnel.cloudproxy.app/v4/connect?project=(PII Removed by Staff)&port=22&newWebsocket=True&zone=europe-west3-a&instance=my-vm&interface=nic0’]
    
    DEBUG: [-1] RECV opcode [2] data_len [332] binary_data[:20] [b’\x00\x01\x00\x00\x01FAdzYv34aHnt4p_']
    
    DEBUG: [-1] CLOSE
    
    DEBUG: [-1] CLOSE
    
    INFO: [-1] Unable to send WebSocket Close message [[Errno 9] Bad file descriptor].
    
    INFO: [-1] Error while receiving from WebSocket.
    
    Traceback (most recent call last):
    
    File “/Users/heyaozh/google-cloud-sdk/lib/googlecloudsdk/api_lib/compute/iap_tunnel_lightweight_websocket.py”, line 243, in run_forever
    
    self._wait_for_socket_to_ready(timeout=WEBSOCKET_RETRY_TIMEOUT_SECS)
    
    […]
    
    OSError: [Errno 9] Bad file descriptor
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
    
    File “/Users/heyaozh/google-cloud-sdk/lib/googlecloudsdk/api_lib/compute/iap_tunnel_websocket_helper.py”, line 272, in _ReceiveFromWebSocket
    
    […]
    
    websocket._exceptions.WebSocketConnectionClosedException: Connection closed while sending data.
    
    Listening on port [60606].
    
  2. VS Code Remote - SSH / ssh -vvv using ProxyCommand ( ~/.ssh/config ):

    • The connection attempt hangs at “Testing if tunnel connection works.”

    • It ultimately results in “Connection timed out during banner exchange” and “The connection timed out.”

    Example Output (Condensed):

    Received install output: local-server-1> Running ssh connection command: ssh -v -T -D 59810 -o ConnectTimeout=60 -o RemoteCommand=none my-vm-gcp
    
    local-server-1> Spawned ssh, pid=64940
    
    OpenSSH_9.9p2, LibreSSL 3.3.6
    
    Picking local unused port [59812].
    
    Testing if tunnel connection works.
    
    Connection timed out during banner exchange
    
    Connection to UNKNOWN port 65535 timed out
    
    local-server-1> ssh child died, shutting down
    
    [21:41:05.715] Resolver error: Error: The connection timed out
    
    […]
    

Steps Already Taken:

  • VM Configuration:

    • VM ( my-vm ) is running in europe-west3-a .

    • SSH daemon ( sshd ) is active and listening on port 22.

    • VM has no external IP address (IAP is required for SSH).

    • VM has the required firewall rule ( 35.235.240.0/20 to tcp:22 ) applied.

    • SSH key-based authentication works correctly via gcloud compute ssh (no password prompt).

  • GCP Project Configuration:

    • iap.googleapis.com API is enabled for project (PII Removed by Staff) .

    • My user account has the IAP-secured Tunnel User role at the project level.

  • Local Environment ( macOS ):

    • Google Cloud SDK has been completely uninstalled (manual directory removal, config deletion, shell cleanup) and cleanly reinstalled.

    • gcloud components update has been performed.

    • No local antivirus, firewall software, or VPN is active.

    • ~/.ssh/config is configured correctly, pointing to the VM’s internal IP, correct user, IdentityFile , and ProxyCommand with --verbosity=none .

    • Attempted to ensure gcloud uses its bundled Python or a clean system Python by commenting out custom Python PATHs.

Conclusion:

The issue appears to be a bug or incompatibility within the gcloud SDK’s IAP tunneling implementation (specifically its Python-based websocket client) on my macOS environment, leading to a Bad file descriptor error during websocket establishment, preventing the IAP tunnel from being fully created for ProxyCommand usage.

Requested Action:

Please investigate this OSError: [Errno 9] Bad file descriptor and WebSocketConnectionClosedException in the gcloud compute start-iap-tunnelcomponent.

You’re able to SSH directly to your GCE VM with gcloud compute ssh, but IAP tunneling via gcloud compute start-iap-tunnel fails on macOS, both in direct CLI usage and via VS Code Remote - SSH. The tunnel initiates a websocket connection but immediately closes, showing OSError: [Errno 9] Bad file descriptor and WebSocketConnectionClosedException, leaving the tunnel broken and ProxyCommand unable to connect. Your VM, firewall, and IAP permissions are correctly configured, and the SDK has been freshly installed, suggesting the issue is likely a macOS-specific bug in gcloud’s IAP websocket implementation. You’re requesting investigation into this tunnel failure so that IAP-based SSH can work reliably.