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

  1. Regenerate the node's keypair (delete and re-run nodeup/bootstrap on the node) so a fresh, valid PKIX public key is sent
  2. Verify the PEM block on the node is a PUBLIC KEY block, not a private key or legacy RSA PUBLIC KEY format
  3. Check node logs and disk health for truncated file writes; re-download node bootstrap assets
  4. 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

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


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