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

  1. 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
  2. Inspect the stored value (kubectl get host ... -o jsonpath='{.spec.publicKey}') and fix PEM armor/indentation/corruption
  3. Ensure the block is -----BEGIN PUBLIC KEY----- (PKIX), not a certificate or SSH-format key
  4. 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

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

Related errors


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