{"record":{"id":"14378c5376be1ce7","repo":"kubernetes/kops","slug":"host-v-did-not-have-public-key","errorCode":null,"errorMessage":"host %v did not have public-key","messagePattern":"host (.+?) did not have public-key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/bootstrap/pkibootstrap/pkiverifier/verifier.go","lineNumber":149,"sourceCode":"\nfunc (v *verifier) getSigningKey(ctx context.Context, tokenData *pkibootstrap.AuthTokenData) (*bootstrap.VerifyResult, crypto.PublicKey, error) {\n\tnodeName := tokenData.Instance\n\tid := types.NamespacedName{\n\t\tNamespace: \"kops-system\",\n\t\tName:      nodeName,\n\t}\n\tvar host kops.Host\n\tif err := v.client.Get(ctx, id, &host); err != nil {\n\t\tif apierrors.IsNotFound(err) {\n\t\t\treturn nil, nil, fmt.Errorf(\"host not found for %v\", id)\n\t\t}\n\t\treturn nil, nil, fmt.Errorf(\"error getting host %v: %w\", id, err)\n\t}\n\n\t// TODO: Check instance-group matches request (does it matter?)\n\n\tif host.Spec.PublicKey == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"host %v did not have public-key\", id)\n\t}\n\tinstanceGroup := host.Spec.InstanceGroup\n\tif instanceGroup == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"host %v did not have spec.instanceGroup\", id)\n\t}\n\tpubKey, err := pki.ParsePEMPublicKey([]byte(host.Spec.PublicKey))\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to parse public key: %w\", err)\n\t}\n\n\tvar sans []string\n\n\tresult := &bootstrap.VerifyResult{\n\t\tNodeName:          nodeName,\n\t\tInstanceGroupName: instanceGroup,\n\t\tCertificateNames:  sans,\n\t}\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/bootstrap/pkibootstrap/pkiverifier/verifier.go#L131-L167","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n// spec:\n//   instanceGroup: nodes\n\n// after\n// spec:\n//   instanceGroup: nodes\n//   publicKey: |\n//     -----BEGIN PUBLIC KEY-----\n//     MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...\n//     -----END PUBLIC KEY-----","handlingStrategy":"validation","validationCode":"var host kops.Host\nif err := c.Get(ctx, types.NamespacedName{Namespace: \"kops-system\", Name: nodeName}, &host); err != nil {\n    return err\n}\nif host.Spec.PublicKey == \"\" {\n    return fmt.Errorf(\"Host %s must have spec.publicKey set to a PEM public key before bootstrap\", nodeName)\n}","typeGuard":"func hostHasPublicKey(h *kops.Host) bool {\n    return h != nil && strings.TrimSpace(h.Spec.PublicKey) != \"\"\n}","tryCatchPattern":"result, err := verifier.VerifyToken(ctx, req, token, body)\nif err != nil {\n    if strings.Contains(err.Error(), \"did not have public-key\") {\n        return fmt.Errorf(\"populate Host spec.publicKey for %s and retry\", nodeName)\n    }\n    return err\n}","preventionTips":["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==\"\")]']"],"tags":["kubernetes","pki","missing-field","configuration"],"backgroundTag":"missing-public-key","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}