kubernetes/kops · error

unable to find specified SSH key %q

Error message

unable to find specified SSH key %q

What it means

When DescribeKeyPairs returns no key pairs at all and the task is marked as referencing an existing key (IsExistingKey) with a non-empty name, kOps fails with "unable to find specified SSH key". This protects against silently creating a new key when the user explicitly said the key already exists.

Source

Thrown at upup/pkg/fi/cloudup/awstasks/sshkey.go:74

func (e *SSHKey) Find(c *fi.CloudupContext) (*SSHKey, error) {
	cloud := awsup.GetCloud(c)

	return e.find(c.Context(), cloud)
}

func (e *SSHKey) find(ctx context.Context, cloud awsup.AWSCloud) (*SSHKey, error) {
	request := &ec2.DescribeKeyPairsInput{
		KeyNames: []string{fi.ValueOf(e.Name)},
	}

	response, err := cloud.EC2().DescribeKeyPairs(ctx, request)
	if err != nil && awsup.AWSErrorCode(err) != "InvalidKeyPair.NotFound" {
		return nil, fmt.Errorf("error listing SSHKeys: %v", err)
	}

	if response == nil || len(response.KeyPairs) == 0 {
		if e.IsExistingKey() && *e.Name != "" {
			return nil, fmt.Errorf("unable to find specified SSH key %q", *e.Name)
		}
		return nil, nil
	}

	if len(response.KeyPairs) != 1 {
		return nil, fmt.Errorf("Found multiple SSHKeys with Name %q", *e.Name)
	}

	k := response.KeyPairs[0]
	actual := &SSHKey{
		ID:             k.KeyPairId,
		Name:           k.KeyName,
		KeyFingerprint: k.KeyFingerprint,
		Tags:           mapEC2TagsToMap(k.Tags),
		Shared:         e.Shared,
	}

	// Avoid spurious changes

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Correct the key name in the cluster spec (kops get instancegroups / cluster.yaml).
  2. Verify the key exists: aws ec2 describe-key-pairs --key-names <name> in the target region.
  3. Import the key if missing: aws ec2 import-key-pair --key-name <name> --public-key-material fileb://id_rsa.pub.
  4. Switch the cluster to a different key or drop the existing-key flag so kOps creates one.

Example fix

// before (cluster spec)
sshKeyName: "admin-prod-key"
// after
sshKeyName: "admin-staging-key" // name that exists in the target region
Defensive patterns

Strategy: validation

Validate before calling

keyName := spec.SSHKeyName
out, err := exec.Command("aws", "ec2", "describe-key-pairs",
    "--region", region, "--key-names", keyName).Output()
if err != nil {
    return fmt.Errorf("SSH key %q does not exist in %s; import it or fix the spec", keyName, region)
}

Type guard

func keyExistsInRegion(keyName, region string) bool {
    out, err := exec.Command("aws", "ec2", "describe-key-pairs", "--region", region, "--key-names", keyName).Output()
    return err == nil && len(out) > 0
}

Prevention

When it happens

Trigger: Spec sets an SSH key by name with existing semantics, but no EC2 key pair with that exact name exists in the target region/account.

Common situations: Typo in the SSH key name in the cluster spec; key exists in a different region; key was deleted out-of-band; running kOps against a different account than where the key was created.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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