kubernetes/kops · error

SSH agent has no keys

Error message

SSH agent has no keys

What it means

The connected ssh-agent returned zero signers: the agent socket is reachable but no identities are loaded (ssh-add -l is empty), so there is no key available to authenticate to the target host.

Source

Thrown at pkg/commands/toolbox_enroll.go:311

	socket := os.Getenv("SSH_AUTH_SOCK")
	if socket == "" {
		return nil, fmt.Errorf("cannot connect to SSH agent; SSH_AUTH_SOCK env variable not set")
	}
	conn, err := net.Dial("unix", socket)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to SSH agent with SSH_AUTH_SOCK %q: %w", socket, err)
	}

	agentClient := agent.NewClient(conn)

	signers, err := agentClient.Signers()
	if err != nil {
		_ = conn.Close()
		return nil, fmt.Errorf("failed to get signers: %w", err)
	}

	if len(signers) == 0 {
		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)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Add a key to the agent: ssh-add ~/.ssh/id_<type>
  2. Confirm keys are loaded: ssh-add -l (should list at least one key)
  3. If re-running after failure, ensure a prior ssh-add -D wasn't executed or the agent restarted
  4. Test SSH manually first: ssh <user>@<host> should succeed using the same agent

Example fix

// before
$ eval $(ssh-agent)
$ kops toolbox enroll ...  # Error: SSH agent has no keys
// after
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_ed25519
$ ssh-add -l   # sanity check: lists the key
$ kops toolbox enroll ...
Defensive patterns

Strategy: validation

Validate before calling

out, err := exec.Command("ssh-add", "-l").Output()
if err != nil || len(bytes.TrimSpace(out)) == 0 {
    return fmt.Errorf("no keys in agent; run ssh-add <key>")
}

Type guard

func agentHasKeys() bool {
    out, err := exec.Command("ssh-add", "-l").Output()
    return err == nil && len(bytes.TrimSpace(out)) > 0
}

Try / catch

host, err := NewSSHHost(ctx, hostAddr, port, user, sudo)
if err != nil && strings.Contains(err.Error(), "SSH agent has no keys") {
    return fmt.Errorf("load a key first: ssh-add ~/.ssh/id_ed25519")
}

Prevention

When it happens

Trigger: agentClient.Signers() returns an empty slice: the agent is running (often freshly started) but ssh-add was never run, or all keys were removed (ssh-add -D), or the forwarded agent belongs to a user/machine with no keys loaded.

Common situations: Starting a new CI job with an agent but forgetting to inject the key; ssh-add keys on a laptop then hopping through a bastion without forwarding; reboot cleared the agent's key cache.

Related errors


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