kubernetes/kops · error

error reading SSH public key files %q: %v

Error message

error reading SSH public key files %q: %v

What it means

When no explicit SSH public keys were given, kops tries to autoload keys from standard locations (e.g. ~/.ssh/id_rsa.pub, ~/.ssh/id_ed25519.pub) and accumulates read errors in a multierr. If every autoload attempt failed and no keys were provided at all, this error aborts the command listing all paths attempted. Cluster creation stops because no SSH credential could be registered.

Source

Thrown at cmd/kops/create_cluster.go:857

			sshPublicKeyPaths := []string{
				"~/.ssh/id_ed25519.pub",
				"~/.ssh/id_rsa.pub",
			}
			var merr error
			for _, sshPublicKeyPath := range sshPublicKeyPaths {
				c.SSHPublicKeys, err = loadSSHPublicKeys(sshPublicKeyPath)
				if err == nil {
					break
				}
				// Don't wrap file-not-found
				if os.IsNotExist(err) {
					klog.V(2).Infof("ssh key not found at %s", sshPublicKeyPath)
				} else {
					merr = multierr.Append(merr, err)
				}
			}
			if merr != nil && len(c.SSHPublicKeys) == 0 {
				return fmt.Errorf("error reading SSH public key files %q: %v", sshPublicKeyPaths, merr)
			}
		}
	}

	if len(c.SSHPublicKeys) != 0 {
		sshCredentialStore, err := clientset.SSHCredentialStore(cluster)
		if err != nil {
			return err
		}

		for _, data := range c.SSHPublicKeys {
			err = sshCredentialStore.AddSSHPublicKey(ctx, data)
			if err != nil {
				return fmt.Errorf("error adding SSH public key: %v", err)
			}
		}
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Generate a key: ssh-keygen -t ed25519 (writes ~/.ssh/id_ed25519.pub).
  2. Pass the key explicitly: --ssh-public-key ~/.ssh/id_rsa.pub.
  3. Fix file permissions (chmod 644 ~/.ssh/*.pub) or HOME resolution in the environment.
  4. Supply the key explicitly on gce/aws too, to avoid relying on autoload behavior.

Example fix

// before
kops create cluster --name c.k8s.local --zones us-east-1a   # no key in ~/.ssh
// after
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519
kops create cluster --name c.k8s.local --zones us-east-1a
Defensive patterns

Strategy: validation

Validate before calling

func ensureSSHPublicKey(explicit string) (string, error) {
	if explicit != "" {
		if _, err := os.Stat(explicit); err != nil {
			return "", fmt.Errorf("ssh key %s missing: %w", explicit, err)
		}
		return explicit, nil
	}
	for _, p := range []string{"~/.ssh/id_ed25519.pub", "~/.ssh/id_rsa.pub"} {
		if expanded, err := homedir.Expand(p); err == nil {
			if _, err := os.Stat(expanded); err == nil {
				return expanded, nil
			}
		}
	}
	return "", fmt.Errorf("no SSH public key found; pass --ssh-public-key")
}

Prevention

When it happens

Trigger: `kops create cluster` without --ssh-public-key on a machine where the default ~/.ssh public key files are absent or unreadable, and the cloud provider is not gce/aws (which skip autoloading).

Common situations: Fresh VM/container with no generated SSH keys; keys generated under nonstandard filenames; HOME unset in CI so ~/.ssh resolves incorrectly; restrictive file permissions.

Related errors


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