{"record":{"id":"04f40efdc09fea00","repo":"kubernetes/kops","slug":"unexpected-key-name","errorCode":null,"errorMessage":"unexpected key name","messagePattern":"unexpected key name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/pkg/server/server.go","lineNumber":339,"sourceCode":"\t\t\tCommonName:   fmt.Sprintf(\"system:node:%s\", id.NodeName),\n\t\t\tOrganization: []string{rbac.NodesGroup},\n\t\t}\n\tcase \"kubelet-server\":\n\t\tissueReq.Subject = pkix.Name{\n\t\t\tCommonName: id.NodeName,\n\t\t}\n\t\tissueReq.AlternateNames = id.CertificateNames\n\t\tissueReq.Type = \"server\"\n\tcase \"kube-proxy\":\n\t\tissueReq.Subject = pkix.Name{\n\t\t\tCommonName: rbac.KubeProxy,\n\t\t}\n\tcase \"kube-router\":\n\t\tissueReq.Subject = pkix.Name{\n\t\t\tCommonName: rbac.KubeRouter,\n\t\t}\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unexpected key name\")\n\t}\n\n\t// This field was added to the protocol in kOps 1.22.\n\tif len(keypairIDs) > 0 {\n\t\tif keypairIDs[issueReq.Signer] != s.keypairIDs[issueReq.Signer] {\n\t\t\treturn \"\", fmt.Errorf(\"request's keypair ID %q for %s didn't match server's %q\", keypairIDs[issueReq.Signer], issueReq.Signer, s.keypairIDs[issueReq.Signer])\n\t\t}\n\t}\n\n\tcert, _, _, err := pki.IssueCert(ctx, issueReq, s.keystore)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"issuing certificate: %v\", err)\n\t}\n\n\treturn cert.AsString()\n}\n\n// recovery is responsible for ensuring we don't exit on a panic.","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/pkg/server/server.go#L321-L357","documentation":"After the allowlist check, issueCert switches on the requested key name to set the certificate subject. A name that passes the allowlist but has no case in the switch indicates an internal inconsistency between certNames and the switch, so the server returns \"unexpected key name\".","triggerScenarios":"The controller was started with a --cert-names value that is not one of the known names handled in the switch (typo, or a name added to the flag but not supported by this kops-controller build).","commonSituations":"Hand-edited controller Deployment args introducing a typo; version skew where a newer client requests a key name the older controller binary does not know; configuration drift after partial upgrades.","solutions":["Correct the --cert-names flag values to the exact supported names (kubelet, kube-router, etcd-client-cilium, etc.)","Upgrade kops-controller to match the kOps version that introduced the requested key name","Regenerate the controller manifest with `kops update cluster` instead of hand-editing"],"exampleFix":"// before\n--cert-names=kubelet,kuberouter\n// after\n--cert-names=kubelet,kube-router","handlingStrategy":"validation","validationCode":"var knownCertNames = map[string]bool{\n    \"kubelet\": true, \"kube-router\": true, \"etcd-client-cilium\": true,\n}\nif !knownCertNames[name] {\n    return fmt.Errorf(\"unknown cert name %q\", name)\n}","typeGuard":"func isKnownCertName(name string) bool {\n    switch name {\n    case \"kubelet\", \"kube-router\", \"etcd-client-cilium\", \"etcd-client-events\":\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unexpected key name\") {\n    log.Printf(\"requested cert name %q unsupported by controller build %s; upgrade controller\", name, version)\n}","preventionTips":["Only pass supported names in --cert-names; copy them from the kops source switch statement","Pin controller and CLI to the same kOps version","Validate Deployment args with `kops toolbox` or CI lint of manifests"],"tags":["certificates","configuration","bootstrap"],"backgroundTag":"unexpected-value","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}