{"record":{"id":"5fd03b6bc1a2d757","repo":"kubernetes/kops","slug":"forbidden-cannot-register-node-name-s-with-cli","errorCode":null,"errorMessage":"Forbidden: cannot register node name '%s' with client cert '%s'","messagePattern":"Forbidden: cannot register node name '(.+?)' with client cert '(.+?)'","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"discovery/pkg/discovery/server.go","lineNumber":162,"sourceCode":"\t\t}\n\t}\n\n\ts.writeJSON(w, http.StatusOK, resp)\n}\n\nfunc (s *Server) handleCreateDiscoveryEndpoint(w http.ResponseWriter, r *http.Request, userInfo *UserInfo) {\n\tuniverseID := r.PathValue(\"universe\")\n\tns := r.PathValue(\"namespace\")\n\n\tvar input api.DiscoveryEndpoint\n\tif err := json.NewDecoder(r.Body).Decode(&input); err != nil {\n\t\thttp.Error(w, \"Invalid request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Validation: ensure the name matches the clientID from the cert\n\tif input.ObjectMeta.Name != \"\" && input.ObjectMeta.Name != userInfo.ClientID {\n\t\thttp.Error(w, fmt.Sprintf(\"Forbidden: cannot register node name '%s' with client cert '%s'\", input.ObjectMeta.Name, userInfo.ClientID), http.StatusForbidden)\n\t\treturn\n\t}\n\n\t// Validation: ensure the namespace in body matches the URL\n\tif input.ObjectMeta.Namespace != ns {\n\t\thttp.Error(w, \"Forbidden: namespace does not match\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tif err := s.Store.UpsertDiscoveryEndpoint(r.Context(), universeID, &input); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Error creating endpoint: %v\", err), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Return the created object\n\ts.writeJSON(w, http.StatusCreated, input)\n}\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/server.go#L144-L180","documentation":"handleCreateDiscoveryEndpoint enforces that a supplied metadata.name matches the ClientID extracted from the client's mTLS certificate. If the body sets a name different from the certificate identity, the server refuses the registration with 403. Sending no name (empty) is allowed and gets the cert identity.","triggerScenarios":"POST create where body's metadata.name is non-empty and != the cert CN/ClientID, e.g. a node trying to register under another node's name or a copied manifest retaining an old name.","commonSituations":"Reusing a manifest from another node without clearing metadata.name; renaming nodes while reusing certs; automation that templates the wrong name; attempting to impersonate another endpoint (correctly blocked).","solutions":["Omit metadata.name in the POST body and let the server use the cert's ClientID.","Set metadata.name exactly equal to the CN/ClientID of the presented client certificate.","Issue/use a certificate whose CN matches the desired endpoint name.","Check for stale hardcoded names in your manifests/templates."],"exampleFix":"// before\nbody := []byte(`{\"metadata\":{\"name\":\"wrong-node\"}}`)\n// after: name matches cert CN\nbody := []byte(`{\"metadata\":{\"name\":\"ip-10-0-0-5\"}}`)","handlingStrategy":"validation","validationCode":"if body.Name != \"\" && body.Name != certClientID {\n    return fmt.Errorf(\"body name %q does not match cert ClientID %q\", body.Name, certClientID)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit metadata.name on create and let the server derive it from the cert","Extract the cert CN at bootstrap and template manifests from it","Never copy manifests between nodes without clearing metadata.name"],"tags":["http","authz","mtls","forbidden","naming"],"backgroundTag":"name-identity-mismatch","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"}