kubernetes/kops · error
parsing key: %v
Error message
parsing key: %v
What it means
issueCert in the kops-controller bootstrap server parses the public key sent by a node from its PEM block via x509.ParsePKIXPublicKey. When the DER bytes do not decode as a valid PKIX public key, the parse error is wrapped as "parsing key: %v" and the certificate request fails.
Source
Thrown at cmd/kops-controller/pkg/server/server.go:300
resp.Certs[name] = cert
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(resp)
klog.Infof("bootstrap %s (req.includeNodeConfig: %t, req.certs.#: %d, req.keypairs.#: %d) success", r.RemoteAddr, req.IncludeNodeConfig, len(req.Certs), len(req.KeypairIDs))
}
func (s *Server) issueCert(ctx context.Context, name string, pubKey string, id *bootstrap.VerifyResult, validHours uint32, keypairIDs map[string]string) (string, error) {
block, _ := pem.Decode([]byte(pubKey))
if block == nil {
return "", fmt.Errorf("decoding pem public key")
}
if block.Type != "RSA PUBLIC KEY" {
return "", fmt.Errorf("unexpected key type %q", block.Type)
}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("parsing key: %v", err)
}
issueReq := &pki.IssueCertRequest{
Signer: fi.CertificateIDCA,
Type: "client",
PublicKey: key,
Validity: time.Hour * time.Duration(validHours),
}
if !s.certNames.Has(name) {
return "", fmt.Errorf("key name not enabled")
}
switch name {
case "etcd-client-cilium":
issueReq.Signer = "etcd-clients-ca-cilium"
issueReq.Subject = pkix.Name{
CommonName: "cilium",
}View on GitHub (pinned to 4c8573c808)
Solutions
- Regenerate the node's keypair (delete and re-run nodeup/bootstrap on the node) so a fresh, valid PKIX public key is sent
- Verify the PEM block on the node is a PUBLIC KEY block, not a private key or legacy RSA PUBLIC KEY format
- Check node logs and disk health for truncated file writes; re-download node bootstrap assets
- Upgrade the node/kops version so client and server agree on key encoding
Example fix
// before (client sending wrong block)
block, _ := pem.Decode(privateKeyPEM)
// after (send the public key, PKIX-encoded)
pubDER, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
pemBlock := &pem.Block{Type: "PUBLIC KEY", Bytes: pubDER}
publicPEM := pem.EncodeToMemory(pemBlock) Defensive patterns
Strategy: validation
Validate before calling
block, _ := pem.Decode(nodeKeyPEM)
if block == nil || block.Type != "PUBLIC KEY" {
return fmt.Errorf("node sent invalid PEM block %v", block)
}
if _, err := x509.ParsePKIXPublicKey(block.Bytes); err != nil {
return fmt.Errorf("node public key invalid: %v", err)
} Type guard
func isPublicKeyPEM(pemBytes []byte) bool {
block, _ := pem.Decode(pemBytes)
if block == nil || block.Type != "PUBLIC KEY" {
return false
}
_, err := x509.ParsePKIXPublicKey(block.Bytes)
return err == nil
} Try / catch
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
log.Printf("rejecting bootstrap request: bad public key: %v", err)
return "", fmt.Errorf("parsing key: %v", err)
} Prevention
- Always regenerate node keypairs on re-bootstrap; never reuse partial key files
- Verify disk health and atomic writes for node key material
- Keep node bootstrap code and controller versions aligned
- Log the key PEM fingerprint (not contents) on failure to aid diagnosis
When it happens
Trigger: A node POSTs to the bootstrap /issueCert endpoint with a key whose PEM payload is corrupt, truncated, or not a PKIX-encoded public key (e.g. private key bytes, garbage, or an unsupported algorithm).
Common situations: Corrupted node key files on disk (partial writes, disk full), nodeup generating or transmitting the wrong key type, tampered/replayed bootstrap requests, or mismatched node bootstrap code from a version skew.
Related errors
- decoding pem public key
- unexpected key type %q
- key name not enabled
- unexpected key name
- request's keypair ID %q for %s didn't match server's %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/c4edbf962a53c3c3.
Report an issue: GitHub.