kubernetes/kops · error
host %v did not have public-key
Error message
host %v did not have public-key
What it means
The Host object exists, but its spec.publicKey field is empty, so the verifier has no PEM public key against which to verify the node's token signature. It fails closed rather than allowing an unsigned/unverifiable bootstrap.
Source
Thrown at pkg/bootstrap/pkibootstrap/pkiverifier/verifier.go:149
func (v *verifier) getSigningKey(ctx context.Context, tokenData *pkibootstrap.AuthTokenData) (*bootstrap.VerifyResult, crypto.PublicKey, error) {
nodeName := tokenData.Instance
id := types.NamespacedName{
Namespace: "kops-system",
Name: nodeName,
}
var host kops.Host
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,
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Populate spec.publicKey on the Host with the node's PEM-encoded public key (e.g. openssl ec -in ec-priv-key.pem -pubout) and re-run bootstrap
- Check the process/controller responsible for setting spec.publicKey and fix why it did not write the key
- Verify the PEM stored is a supported key type (ECDSA prime256v1; Go does not support secp256k1)
- Recreate the Host object from the correct template if it was created incomplete
Example fix
// before // spec: // instanceGroup: nodes // after // spec: // instanceGroup: nodes // publicKey: | // -----BEGIN PUBLIC KEY----- // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... // -----END PUBLIC KEY-----
Defensive patterns
Strategy: validation
Validate before calling
var host kops.Host
if err := c.Get(ctx, types.NamespacedName{Namespace: "kops-system", Name: nodeName}, &host); err != nil {
return err
}
if host.Spec.PublicKey == "" {
return fmt.Errorf("Host %s must have spec.publicKey set to a PEM public key before bootstrap", nodeName)
} Type guard
func hostHasPublicKey(h *kops.Host) bool {
return h != nil && strings.TrimSpace(h.Spec.PublicKey) != ""
} Try / catch
result, err := verifier.VerifyToken(ctx, req, token, body)
if err != nil {
if strings.Contains(err.Error(), "did not have public-key") {
return fmt.Errorf("populate Host spec.publicKey for %s and retry", nodeName)
}
return err
} Prevention
- Use a Host manifest template that always includes spec.publicKey
- Validate Host objects with a webhook/admission check for required fields
- Generate and inject the public key in the same provisioning step that creates the Host
- Audit Hosts with empty publicKey periodically: kubectl get host -n kops-system -o json | jq '[.items[] | select(.spec.publicKey=="")]']
When it happens
Trigger: VerifyToken -> getSigningKey fetches a Host whose spec.PublicKey == "" — the Host was created without a publicKey, a controller cleared it, or a manifest template omitted the field.
Common situations: Hand-written Host manifest missing spec.publicKey; automation (e.g. cloud integration) created the Host before writing the machine's public key; key provisioning step failed silently; a kops version change altered how/where the key is populated.
Related errors
- host %v did not have spec.instanceGroup
- building kubernetes client for node labeler: %w
- clientset is not initialized
- host not found for %v
- failed to parse public key: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/14378c5376be1ce7.
Report an issue: GitHub.