kubernetes/kops · error

Unauthorized

Error message

Unauthorized

What it means

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.

Source

Thrown at discovery/pkg/discovery/server.go:82

	// Get DiscoveryEndpoint
	s.mux.HandleFunc("GET /{universe}/apis/discovery.kops.k8s.io/v1alpha1/namespaces/{namespace}/discoveryendpoints/{name}", s.withAuth(s.handleGetDiscoveryEndpoint))

	// Apply (Patch) DiscoveryEndpoint
	s.mux.HandleFunc("PATCH /{universe}/apis/discovery.kops.k8s.io/v1alpha1/namespaces/{namespace}/discoveryendpoints/{name}", s.withAuth(s.handleApplyDiscoveryEndpoint))
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.mux.ServeHTTP(w, r)
}

func (s *Server) withAuth(next func(http.ResponseWriter, *http.Request, *UserInfo)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		universeID := r.PathValue("universe")
		userInfo, err := AuthenticateClientToUniverse(r, universeID)
		if err != nil {
			klog.Warningf("Unauthorized access attempt to universe %s: %v", universeID, err)
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next(w, r, userInfo)
	}
}

// Handlers

func (s *Server) handleAPIGroupList(w http.ResponseWriter, r *http.Request, _ *UserInfo) {
	resp := metav1.APIGroupList{
		TypeMeta: metav1.TypeMeta{Kind: "APIGroupList", APIVersion: "v1"},
		Groups: []metav1.APIGroup{
			{
				Name: "discovery.kops.k8s.io",
				Versions: []metav1.GroupVersionForDiscovery{
					{GroupVersion: "discovery.kops.k8s.io/v1alpha1", Version: "v1alpha1"},
				},
				PreferredVersion: metav1.GroupVersionForDiscovery{

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the client presents a valid TLS client certificate (configure --cert/--key on the client).
  2. Check the cert is signed by the CA trusted for the target universe and is not expired.
  3. Verify the cert's CN/ClientID is registered/authorized for the universe in the URL path.
  4. Confirm the universe ID in the request URL matches the one the cert was issued for.

Example fix

// before: client connects without cert
client := &http.Client{}
// after: mTLS client
client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: caPool}}}}
Defensive patterns

Strategy: validation

Validate before calling

if certPEM == "" { return errors.New("no client certificate configured") }
cert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil { return fmt.Errorf("invalid client cert: %w", err) }
if time.Now().After(leaf.NotAfter) { return errors.New("client cert expired") }

Type guard

func certLooksValid(leaf *x509.Certificate) bool {
    return leaf != nil && time.Now().Before(leaf.NotAfter) && time.Now().After(leaf.NotBefore)
}

Try / catch

resp, err := client.Do(req)
if err == nil && resp.StatusCode == http.StatusUnauthorized {
    return fmt.Errorf("auth rejected for universe %s: check client cert, expiry, and CN/universe mapping", universe)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/590f5e6e0548d429. Report an issue: GitHub.