kubernetes/kops · error

reading private key %q: %v

Error message

reading private key %q: %v

What it means

When toolbox dump is asked to use a private key (for SSH bastion tunneling), it first reads the key file from disk. This error wraps any os.ReadFile failure — missing file, permission denied, or path issues — with the resolved path and the underlying OS error.

Source

Thrown at cmd/kops/toolbox_dump.go:164

		resourceMap, err := resourceops.ListResources(cloud, cluster)
		if err != nil {
			return err
		}
		d, err := resources.BuildDump(ctx, cloud, resourceMap)
		if err != nil {
			return err
		}
		cloudResources = d
	}

	if options.Dir != "" {
		privateKeyPath := options.PrivateKey
		if strings.HasPrefix(privateKeyPath, "~/") {
			privateKeyPath = filepath.Join(os.Getenv("HOME"), privateKeyPath[2:])
		}
		key, err := os.ReadFile(privateKeyPath)
		if err != nil {
			return fmt.Errorf("reading private key %q: %v", privateKeyPath, err)
		}

		parsedKey, err := ssh.ParseRawPrivateKey(key)
		if err != nil {
			return fmt.Errorf("parsing private key %q: %v", privateKeyPath, err)
		}

		signer, err := ssh.NewSignerFromKey(parsedKey)
		if err != nil {
			return fmt.Errorf("creating signer for private key %q: %v", privateKeyPath, err)
		}

		contextName := cluster.ObjectMeta.Name
		clientGetter := genericclioptions.NewConfigFlags(true)
		clientGetter.Context = &contextName

		var nodes corev1.NodeList

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the resolved path printed in the error exists: ls -la <path>.
  2. Fix file permissions: chmod 600 <keyfile> and ensure your user owns it.
  3. Set HOME correctly (or pass an absolute path) when running under cron/CI where ~ cannot expand.
  4. Pass the private key file, not the .pub counterpart, and confirm the underlying OS error (No such file vs permission denied) before further steps.

Example fix

// before
kops toolbox dump --name c.k8s.local --private-key ~/keys/id_rsa  # HOME unset -> path '/keys/id_rsa' missing
// after
kops toolbox dump --name c.k8s.local --private-key /home/me/keys/id_rsa
chmod 600 /home/me/keys/id_rsa
Defensive patterns

Strategy: validation

Validate before calling

KEY_PATH="${KEY_PATH/#\~/$HOME}"
if [ ! -f "$KEY_PATH" ]; then echo "private key not found: $KEY_PATH"; exit 1; fi
if [ ! -r "$KEY_PATH" ]; then echo "private key unreadable (check perms/owner)"; exit 1; fi

Try / catch

key, err := os.ReadFile(privateKeyPath)
if err != nil {
    return fmt.Errorf("reading private key %q (check path, permissions, HOME): %w", privateKeyPath, err)
}

Prevention

When it happens

Trigger: --private-key (options.PrivateKey) is set, the path is expanded (~/*), and os.ReadFile fails: the file does not exist at the resolved path, the user lacks read permission, or the path is a directory.

Common situations: Passing a path that only exists on another machine; the '~' expansion fails because $HOME is unset in cron/CI; permissions tightened by SSH tooling (600 on a key owned by another user); pointing at the .pub file or a directory instead of the private key.

Related errors


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