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:
-
Direct
gcloud compute start-iap-tunnelcommand 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]. -
-
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.