kubernetes/kops · error
failed to parse public key: %w
Error message
failed to parse public key: %w
What it means
The Host's spec.publicKey is non-empty but could not be parsed as a PEM public key by pki.ParsePEMPublicKey. The wrapped error from the parser indicates the actual problem (bad PEM armor, unsupported key type, truncated data).
Source
Thrown at pkg/bootstrap/pkibootstrap/pkiverifier/verifier.go:157
if err := v.client.Get(ctx, id, &host); err != nil {
if apierrors.IsNotFound(err) {
return nil, nil, fmt.Errorf("host not found for %v", id)
}
return nil, nil, fmt.Errorf("error getting host %v: %w", id, err)
}
// TODO: Check instance-group matches request (does it matter?)
if host.Spec.PublicKey == "" {
return nil, nil, fmt.Errorf("host %v did not have public-key", id)
}
instanceGroup := host.Spec.InstanceGroup
if instanceGroup == "" {
return nil, nil, fmt.Errorf("host %v did not have spec.instanceGroup", id)
}
pubKey, err := pki.ParsePEMPublicKey([]byte(host.Spec.PublicKey))
if err != nil {
return nil, nil, fmt.Errorf("failed to parse public key: %w", err)
}
var sans []string
result := &bootstrap.VerifyResult{
NodeName: nodeName,
InstanceGroupName: instanceGroup,
CertificateNames: sans,
}
return result, pubKey.Key, nil
}
func verifySignature(signingKey crypto.PublicKey, payload []byte, signature []byte) bool {
attestHash := sha256.Sum256(payload)
switch signingKey := signingKey.(type) {
case *ecdsa.PublicKey:
klog.Infof("attestHash %x", attestHash)View on GitHub (pinned to 4c8573c808)
Solutions
- Regenerate with supported tooling: openssl ecparam -name prime256v1 -genkey -noout -out key.pem && openssl ec -in key.pem -pubout, then store the BEGIN PUBLIC KEY block in spec.publicKey
- Inspect the stored value (kubectl get host ... -o jsonpath='{.spec.publicKey}') and fix PEM armor/indentation/corruption
- Ensure the block is -----BEGIN PUBLIC KEY----- (PKIX), not a certificate or SSH-format key
- Use an ECDSA key type supported by Go/verifier (the signature check only supports *ecdsa.PublicKey)
Example fix
// before (SSH format, unparsable) // spec: // publicKey: ssh-rsa AAAAB3Nza... // after (PKIX ECDSA PEM) // spec: // publicKey: | // -----BEGIN PUBLIC KEY----- // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... // -----END PUBLIC KEY-----
Defensive patterns
Strategy: validation
Validate before calling
pub, err := pki.ParsePEMPublicKey([]byte(host.Spec.PublicKey))
if err != nil {
return fmt.Errorf("spec.publicKey for %s is not a valid PKIX PEM public key: %w", nodeName, err)
}
if _, ok := pub.Key.(*ecdsa.PublicKey); !ok {
return fmt.Errorf("spec.publicKey for %s must be an ECDSA key", nodeName)
} Type guard
func isParseableECDSAPublicKey(pemStr string) bool {
k, err := pki.ParsePEMPublicKey([]byte(pemStr))
if err != nil {
return false
}
_, ok := k.Key.(*ecdsa.PublicKey)
return ok
} Try / catch
result, err := verifier.VerifyToken(ctx, req, token, body)
if err != nil {
var perr *pki.ParseError // or inspect wrapped error
if strings.Contains(err.Error(), "failed to parse public key") {
return fmt.Errorf("fix spec.publicKey PEM format on the Host object: %w", err)
}
return err
} Prevention
- Store only PKIX 'BEGIN PUBLIC KEY' ECDSA (prime256v1) blocks in spec.publicKey
- Use YAML block scalars (|) with correct indentation to avoid base64 corruption
- Never store SSH-format keys or certificates in spec.publicKey
- Pre-validate the PEM with pki.ParsePEMPublicKey at Host creation time
When it happens
Trigger: VerifyToken -> getSigningKey calls ParsePEMPublicKey on host.Spec.PublicKey and it errors: field holds a private key instead of a public key, wrong PEM block type (CERTIFICATE instead of PUBLIC KEY), SSH-format key instead of PKIX PEM, whitespace/base64 corruption from YAML indentation, or unsupported curve (e.g. secp256k1).
Common situations: Pasting an SSH authorized_keys line instead of a PKIX PEM public key; YAML multiline indentation mangling the base64 body; storing the certificate rather than the public key; generating keys with an algorithm Go's crypto/x509 cannot parse.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- error converting public key to x509: %w
- host %v did not have public-key
- unrecognized certificate option: %v
- unrecognized certificate option: %q
- error parsing KOPS_RSA_PRIVATE_KEY_SIZE=%s as integer
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/2c8bb1c7d9e40f4c.
Report an issue: GitHub.