{"record":{"id":"590f5e6e0548d429","repo":"kubernetes/kops","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"discovery/pkg/discovery/server.go","lineNumber":82,"sourceCode":"\n\t// Get DiscoveryEndpoint\n\ts.mux.HandleFunc(\"GET /{universe}/apis/discovery.kops.k8s.io/v1alpha1/namespaces/{namespace}/discoveryendpoints/{name}\", s.withAuth(s.handleGetDiscoveryEndpoint))\n\n\t// Apply (Patch) DiscoveryEndpoint\n\ts.mux.HandleFunc(\"PATCH /{universe}/apis/discovery.kops.k8s.io/v1alpha1/namespaces/{namespace}/discoveryendpoints/{name}\", s.withAuth(s.handleApplyDiscoveryEndpoint))\n}\n\nfunc (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\ts.mux.ServeHTTP(w, r)\n}\n\nfunc (s *Server) withAuth(next func(http.ResponseWriter, *http.Request, *UserInfo)) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\tuniverseID := r.PathValue(\"universe\")\n\t\tuserInfo, err := AuthenticateClientToUniverse(r, universeID)\n\t\tif err != nil {\n\t\t\tklog.Warningf(\"Unauthorized access attempt to universe %s: %v\", universeID, err)\n\t\t\thttp.Error(w, \"Unauthorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t\tnext(w, r, userInfo)\n\t}\n}\n\n// Handlers\n\nfunc (s *Server) handleAPIGroupList(w http.ResponseWriter, r *http.Request, _ *UserInfo) {\n\tresp := metav1.APIGroupList{\n\t\tTypeMeta: metav1.TypeMeta{Kind: \"APIGroupList\", APIVersion: \"v1\"},\n\t\tGroups: []metav1.APIGroup{\n\t\t\t{\n\t\t\t\tName: \"discovery.kops.k8s.io\",\n\t\t\t\tVersions: []metav1.GroupVersionForDiscovery{\n\t\t\t\t\t{GroupVersion: \"discovery.kops.k8s.io/v1alpha1\", Version: \"v1alpha1\"},\n\t\t\t\t},\n\t\t\t\tPreferredVersion: metav1.GroupVersionForDiscovery{","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/server.go#L64-L100","documentation":"The withAuth middleware calls AuthenticateClientToUniverse, which validates the client's TLS client certificate against the requested universe. On any authentication failure the server logs a warning and responds 401 'Unauthorized'. This is the gate for all authenticated API routes.","triggerScenarios":"Any request to authenticated routes (/{universe}/apis, discoveryendpoints list/create/patch) where the client cert is missing, untrusted/unknown CA, expired, or its CN/ClientID is not authorized for that universe.","commonSituations":"Client not presenting its mTLS keypair; cluster node using a cert from a different universe; expired node certificate; server CA rotated and clients still present old certs; wrong universe path segment in the URL.","solutions":["Ensure the client presents a valid TLS client certificate (configure --cert/--key on the client).","Check the cert is signed by the CA trusted for the target universe and is not expired.","Verify the cert's CN/ClientID is registered/authorized for the universe in the URL path.","Confirm the universe ID in the request URL matches the one the cert was issued for."],"exampleFix":"// before: client connects without cert\nclient := &http.Client{}\n// after: mTLS client\nclient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: caPool}}}}","handlingStrategy":"validation","validationCode":"if certPEM == \"\" { return errors.New(\"no client certificate configured\") }\ncert, err := tls.X509KeyPair(certPEM, keyPEM)\nif err != nil { return fmt.Errorf(\"invalid client cert: %w\", err) }\nif time.Now().After(leaf.NotAfter) { return errors.New(\"client cert expired\") }","typeGuard":"func certLooksValid(leaf *x509.Certificate) bool {\n    return leaf != nil && time.Now().Before(leaf.NotAfter) && time.Now().After(leaf.NotBefore)\n}","tryCatchPattern":"resp, err := client.Do(req)\nif err == nil && resp.StatusCode == http.StatusUnauthorized {\n    return fmt.Errorf(\"auth rejected for universe %s: check client cert, expiry, and CN/universe mapping\", universe)\n}","preventionTips":["Rotate client certificates before expiry","Verify cert CN matches the endpoint name/universe you register under","Confirm the server trusts your CA before deploying nodes","Include universe in a connectivity smoke test at node bootstrap"],"tags":["http","auth","mtls","client-certificate"],"backgroundTag":"client-certificate-auth-failed","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"}