kubernetes/kops · error

keypair has no certificate

Error message

keypair has no certificate

What it means

This error is returned by promoteKeypair when the `kops promote keypair` command is asked to promote a specific keypair (by ID) whose item exists in the keyset but has no associated certificate. A keypair without a certificate cannot serve as the primary/active key because clients and the control plane verify identities via the certificate, so kOps refuses to promote it. It is a safety check to prevent making a half-created (certificate-only not yet issued) keypair the cluster's active key.

Source

Thrown at cmd/kops/promote_keypair.go:188

					highestCandidateId = itemId
				}
			}
		}

		keypairID = highestCandidateId.String()
		if keypairID == keyset.Primary.Id {
			fmt.Fprintf(out, "No %s keypair newer than current primary %s\n", name, keypairID)
			return nil
		}
	} else if item := keyset.Items[keypairID]; item != nil {
		if item.DistrustTimestamp != nil {
			return fmt.Errorf("keypair is distrusted")
		}
		if item.PrivateKey == nil {
			return fmt.Errorf("keypair has no private key")
		}
		if item.Certificate == nil {
			return fmt.Errorf("keypair has no certificate")
		}
	} else {
		return fmt.Errorf("keypair not found")
	}

	keyset.Primary = keyset.Items[keypairID]
	err = keyStore.StoreKeyset(ctx, name, keyset)
	if err != nil {
		return fmt.Errorf("writing keyset: %v", err)
	}

	fmt.Fprintf(out, "Promoted %s %s\n", name, keypairID)
	return nil
}

func completePromoteKeyset(ctx context.Context, f commandutils.Factory, options *PromoteKeypairOptions, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
	commandutils.ConfigureKlogForCompletion()

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Wait for the keypair's certificate to be issued (re-run rotation/creation) and verify with `kops get keypairs <name> --type <keyset>` that the ID has a certificate, then re-run the promote.
  2. If keypairID was specified manually, omit it and let promoteKeypair auto-select the highest candidate (it only picks items with PrivateKey AND Certificate, excluding distrusted ones).
  3. If the keyset item is permanently incomplete (e.g. corrupted store state), delete the broken keypair entry (`kops delete keypair <name> <keypairID> --yes`) or re-import/reissue the keyset, then promote a valid ID.
  4. Inspect the keyset backing store directly (state store path for the keyset) to confirm the certificate file is present and not empty; restore it if it was lost.

Example fix

// before: promoting an incomplete keypair by explicit ID
// kops promote keypair ca 3   ->  "keypair has no certificate"
// after: let kOps pick a fully issued candidate
// kops promote keypair ca     (auto-selects newest keypair with cert + private key)
// or verify first:
// kops get keypairs ca --type ca   # confirm the target ID shows a certificate before promoting
Defensive patterns

Strategy: validation

Validate before calling

item, ok := keyset.Items[keypairID]
if ok && item.DistrustTimestamp == nil && item.PrivateKey != nil && item.Certificate != nil {
    // safe to promote
}
// or CLI-side: kops get keypairs <name> and confirm the target ID has a certificate before promoting

Type guard

func promotable(item *fi.KeysetItem) bool {
	return item != nil && item.DistrustTimestamp == nil && item.PrivateKey != nil && item.Certificate != nil
}

Prevention

When it happens

Trigger: Running `kops promote keypair <name> <keypairID>` (or calling RunPromoteKeypair with a non-empty KeypairID) where keyset.Items[keypairID] exists but item.Certificate == nil — typically a keypair created/rotated whose certificate issuance has not completed, or a keypair item that only holds a private key.

Common situations: Operators mid-rotation who grabbed a keypair ID from `kops get keypairs` too early, before the new keypair's certificate was issued; keyset entries left incomplete after a failed or interrupted rotation; manual edits or partial state in the keyset store (e.g. S3/base-store) that dropped the certificate.

Understand the failure class

Related errors


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