kubernetes/kops · error
could not parse private key
Error message
could not parse private key
What it means
parsePEMPublicKey iterates pem.Decode over the input; when pem.Decode returns nil block it means the input contained no valid PEM-formatted block at all, so the function gives up. Despite the wording, it is raised for ANY key material (public or private) that is not PEM-encoded. kOps uses this when parsing key data for cluster PKI operations.
Source
Thrown at pkg/pki/publickey.go:47
k, err := parsePEMPublicKey(data)
if err != nil {
return nil, err
}
if k == nil {
return nil, nil
}
return &PublicKey{Key: k}, nil
}
type PublicKey struct {
Key crypto.PublicKey
}
func parsePEMPublicKey(pemData []byte) (crypto.PublicKey, error) {
for {
block, rest := pem.Decode(pemData)
if block == nil {
return nil, fmt.Errorf("could not parse private key")
}
switch block.Type {
case "RSA PUBLIC KEY":
k, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, err
}
return k, nil
case "PUBLIC KEY":
k, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
return k.(crypto.PublicKey), nil
default:
klog.Infof("Ignoring unexpected PEM block: %q", block.Type)
}View on GitHub (pinned to 4c8573c808)
Solutions
- Verify the input includes full PEM armor ('-----BEGIN ... KEY-----' through '-----END ... KEY-----')
- If you only have raw base64/DER key bytes, wrap them in PEM headers with pem.EncodeToMemory before calling ParsePEMPublicKey
- Check for truncated data at the source (config file, secret store) and re-export the key
Example fix
// before
k, err := pki.ParsePEMPublicKey(base64KeyBytes)
// after
pemData := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: derBytes})
k, err := pki.ParsePEMPublicKey(pemData) Defensive patterns
Strategy: validation
Validate before calling
func isPEM(data []byte) bool {
block, _ := pem.Decode(data)
return block != nil
}
if !isPEM(keyData) {
return fmt.Errorf("input is not PEM-encoded; missing BEGIN/END headers")
}
key, err := pki.ParsePEMPublicKey(keyData) Type guard
func hasPEMHeader(s string) bool {
return strings.HasPrefix(strings.TrimSpace(s), "-----BEGIN ")
} Prevention
- Always store keys with full PEM armor, never stripped headers
- Never pre-base64-decode PEM data before passing it to kops PKI functions
- Validate with `openssl pkey -pubin -in key.pem -noout` before use
When it happens
Trigger: Calling ParsePEMPublicKey with raw base64 key bytes, a DER-encoded key, a key with the BEGIN/END headers stripped, or an empty/whitespace-only string; also a corrupted file where the '-----BEGIN' header line is truncated.
Common situations: Storing keys in config without the PEM armor headers, copy-paste errors losing the first line, base64-decoding the key before passing it in, or reading a truncated secret from a YAML/etcd store.
Related errors
- failed to parse public key: %w
- error writing SSL private key: %v
- encoding public key %s: %v
- failed parsing PEM block from EkPub %q
- unknown CA %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/0db93f892297d982.
Report an issue: GitHub.