hashicorp/terraform · error

Error creating new client connection via proxy: %s

Error message

Error creating new client connection via proxy: %s

What it means

Raised in BastionConnectFunc when ssh.NewClientConn(pConn, bAddr, bConf) fails after the HTTP proxy tunnel to the bastion was successfully established. The proxy CONNECT succeeded, but the SSH protocol handshake (key exchange, authentication) over that tunneled connection failed.

Source

Thrown at internal/communicator/ssh/communicator.go:852

		// Wrap connection to bastion server if proxy server is configured
		if p != nil {
			var pConn net.Conn
			var bConn ssh.Conn
			var bChans <-chan ssh.NewChannel
			var bReq <-chan *ssh.Request

			RegisterDialerType()
			pConn, err = newHttpProxyConn(p, bAddr)

			if err != nil {
				return nil, fmt.Errorf("Error connecting to proxy: %s", err)
			}

			bConn, bChans, bReq, err = ssh.NewClientConn(pConn, bAddr, bConf)

			if err != nil {
				return nil, fmt.Errorf("Error creating new client connection via proxy: %s", err)
			}

			bastion = ssh.NewClient(bConn, bChans, bReq)
		} else {
			bastion, err = ssh.Dial(bProto, bAddr, bConf)
		}

		if err != nil {
			return nil, fmt.Errorf("Error connecting to bastion: %s", err)
		}

		log.Printf("[DEBUG] Connecting via bastion (%s) to host: %s", bAddr, addr)
		conn, err := bastion.Dial(proto, addr)
		if err != nil {
			bastion.Close()
			return nil, err
		}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Verify bastion_user, bastion_private_key, and bastion_password are correct for the bastion host.
  2. Confirm the bastion address and port (bAddr) the proxy is tunneling to is correct.
  3. Check the bastion sshd allows the key exchange algorithms supported by the Go SSH client.
  4. Test SSH to the bastion manually through the proxy to isolate the handshake failure.

Example fix

// before
connection {
  bastion_host = var.bastion
  proxy_host   = var.proxy
}

// after
connection {
  bastion_host       = var.bastion
  bastion_user       = "ec2-user"
  bastion_private_key = file("~/.ssh/bastion_key")
  proxy_host         = var.proxy
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate bastion SSH credentials through the proxy before the full run
func validateBastionViaProxy(proxyURL, bastionAddr, user, privateKey string) error {
    // Use a quick SSH dial test through the proxy to catch auth/handshake issues early
    signer, err := ssh.ParsePrivateKey([]byte(privateKey))
    if err != nil {
        return fmt.Errorf("invalid bastion private key: %w", err)
    }
    config := &ssh.ClientConfig{
        User:            user,
        Auth:            []ssh.AuthMethod{ssh.PublicKeys(signer)},
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
        Timeout:         10 * time.Second,
    }
    // (dial through proxy omitted for brevity)
    _ = config
    return nil
}

Prevention

When it happens

Trigger: The proxy tunnel is open but the SSH handshake to the bastion fails: wrong bastion credentials, unsupported SSH key exchange algorithm, bastion sshd config mismatch, or the bastion private key is invalid for the tunneled connection.

Common situations: bastion_private_key does not match the bastion's authorized keys, bastion_user is wrong, the bastion sshd has restrictive algorithm/KexAlgorithms settings incompatible with the Go x/crypto/ssh client, or the proxy tunneled to the wrong port.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/46d5bb824458902d. Report an issue: GitHub.