kubernetes/kops · error

failed to SSH to %q (with user %q): %w

Error message

failed to SSH to %q (with user %q): %w

What it means

With agent-based auth configured, ssh.Dial to host:port failed — TCP unreachable, SSH handshake failure, host unreachable, or the server rejected the agent key (auth attempts exhausted). The HostKeyCallback here accepts any host key, so this is not a host-key failure.

Source

Thrown at pkg/commands/toolbox_enroll.go:329

		return nil, fmt.Errorf("SSH agent has no keys")
	}

	sshConfig := &ssh.ClientConfig{
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			klog.Warningf("accepting SSH key %v for %q", key, hostname)
			return nil
		},
		Auth: []ssh.AuthMethod{
			// Use a callback rather than PublicKeys so we only consult the
			// agent once the remote server wants it.
			ssh.PublicKeysCallback(agentClient.Signers),
		},
		User: sshUser,
	}
	// Use net.JoinHostPort so that IPv6 addresses are bracketed correctly.
	sshClient, err := ssh.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(sshPort)), sshConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to SSH to %q (with user %q): %w", host, sshUser, err)
	}
	return &SSHHost{
		hostname:  host,
		sshClient: sshClient,
		sudo:      sudo,
	}, nil
}

func (s *SSHHost) readFile(ctx context.Context, path string) ([]byte, error) {
	p := vfs.NewSSHPath(s.sshClient, s.hostname, path, s.sudo)

	return p.ReadFile(ctx)
}

func (s *SSHHost) writeFile(ctx context.Context, path string, data io.ReadSeeker) error {
	p := vfs.NewSSHPath(s.sshClient, s.hostname, path, s.sudo)
	return p.WriteFile(ctx, data, nil)
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Test connectivity: nc -vz <host> <port> and ssh -p <port> <user>@<host>
  2. Verify security group / firewall allows TCP 22 (or custom port) from your source IP
  3. Confirm the agent key is in the target user's authorized_keys
  4. Check the wrapped error: 'connection refused' vs 'handshake failed: ssh: unable to authenticate' points to port vs key problems

Example fix

// before
sshHost, err := NewSSHHost(ctx, "10.0.0.5", 2022, "root", true)  // port 2022 blocked
// after
# verify first: ssh -p 22 ubuntu@10.0.0.5
sshHost, err := NewSSHHost(ctx, "10.0.0.5", 22, "ubuntu", true)
Defensive patterns

Strategy: retry

Validate before calling

if err := exec.Command("ssh", "-p", strconv.Itoa(port),
    "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=no",
    user+"@"+host, "true").Run(); err != nil {
    return fmt.Errorf("prerequisite ssh to %s@%s:%d failed: %w", user, host, port, err)
}

Type guard

func sshReachable(host string, port int) bool {
    conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), 5*time.Second)
    if err != nil { return false }
    conn.Close()
    return true
}

Try / catch

var sshHost *SSHHost
err := retry.Do(func() error {
    sshHost, err = NewSSHHost(ctx, hostAddr, port, user, sudo)
    return err
}, retry.Attempts(3), retry.Delay(5*time.Second))
if err != nil {
    return fmt.Errorf("ssh to %q unreachable after retries; check firewall/key auth: %w", hostAddr, err)
}

Prevention

When it happens

Trigger: Wrong host/IP or port (default 22 not open), security group/firewall blocking SSH, host powered off or not yet provisioned, the SSH user lacks authorized_keys on the target, or the agent key isn't authorized on the host.

Common situations: Enrolling a freshly created VM before its network/security-group rules allow SSH; using the internal vs external IP incorrectly; enrolling with a user other than the one holding the authorized key (e.g. root vs admin on cloud images).

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/78630645023bbfdf. Report an issue: GitHub.