{"record":{"id":"7ffc7fa8d47a5665","repo":"kubernetes/kops","slug":"no-client-certificate-presented","errorCode":null,"errorMessage":"no client certificate presented","messagePattern":"no client certificate presented","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/pkg/discovery/auth.go","lineNumber":41,"sourceCode":"\t\"fmt\"\n\t\"net/http\"\n)\n\ntype UserInfo struct {\n\tUniverseID string\n\tClientID   string\n}\n\n// AuthenticateClientToUniverse extracts the Universe ID and Client ID from the mTLS connection.\n// The Universe ID is defined as the SHA256 hash of the root CA certificate (DER bytes)\n// presented in the client's certificate chain.\n// The Client ID is taken from the Common Name (CN) of the leaf certificate.\nfunc AuthenticateClientToUniverse(r *http.Request, universeID string) (*UserInfo, error) {\n\tif r.TLS == nil {\n\t\treturn nil, fmt.Errorf(\"no TLS connection\")\n\t}\n\tif len(r.TLS.PeerCertificates) == 0 {\n\t\treturn nil, fmt.Errorf(\"no client certificate presented\")\n\t}\n\n\t// Verify the chain is valid, though we don't validate that the CA certificate is trusted.\n\tvar verifiedChains [][]*x509.Certificate\n\t{\n\t\tpeerCertificates := r.TLS.PeerCertificates\n\n\t\topts := x509.VerifyOptions{\n\t\t\tRoots:         x509.NewCertPool(),\n\t\t\tIntermediates: x509.NewCertPool(),\n\t\t\tKeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},\n\t\t}\n\n\t\tfor i := 1; i < len(peerCertificates); i++ {\n\t\t\tif i == len(peerCertificates)-1 {\n\t\t\t\t// Last cert is the root\n\t\t\t\topts.Roots.AddCert(peerCertificates[i])\n\t\t\t} else {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/auth.go#L23-L59","documentation":"The mTLS connection state exists but carries no peer certificate chain (r.TLS.PeerCertificates is empty), so AuthenticateClientToUniverse cannot identify the client. The server requires a client certificate to derive Universe/Client IDs and rejects requests without one.","triggerScenarios":"A TLS client connects without presenting a certificate (no ClientCert requested or client skipped it); TLS config lacks RequestClientCert/RequireAndVerifyClientCert; the client cert failed to load client-side and the handshake proceeded anonymously.","commonSituations":"Server tls.Config missing ClientAuth: tls.RequireAndVerifyClientCert; client built without TLSClientConfig.Certificates; mutual-TLS terminated at proxy then re-originated without a cert; curl test without --cert/--key.","solutions":["Configure the server's tls.Config with ClientAuth: tls.RequireAndVerifyClientCert and ClientCAs set to the trust pool.","Ensure clients present a certificate (set TLSClientConfig.Certificates in Go, --cert/--key in curl).","If behind a proxy, use TLS passthrough or have the proxy re-present a client cert to the backend.","Test the handshake: openssl s_client -connect host:443 -cert client.crt -key client.key and confirm a peer cert reaches the server."],"exampleFix":"// before\ncfg := &tls.Config{ClientCAs: caPool} // client certs requested but not required\n// after\ncfg := &tls.Config{ClientCAs: caPool, ClientAuth: tls.RequireAndVerifyClientCert}","handlingStrategy":"validation","validationCode":"// enforce client certs at server startup\ncfg := &tls.Config{\n    ClientCAs:  caPool,\n    ClientAuth: tls.RequireAndVerifyClientCert,\n}\nserver := &http.Server{Addr: \":443\", TLSConfig: cfg}","typeGuard":"func hasClientCert(r *http.Request) bool {\n    return r.TLS != nil && len(r.TLS.PeerCertificates) > 0\n}","tryCatchPattern":"// Go: reject missing client certs with 401\nu, err := AuthenticateClientToUniverse(r, universeID)\nif err != nil {\n    http.Error(w, \"client certificate required\", http.StatusUnauthorized)\n    return\n}","preventionTips":["Always set ClientAuth: tls.RequireAndVerifyClientCert on mTLS servers.","Ensure clients always load a certificate (fail fast on keypair load errors).","Use TLS passthrough at LBs so the client cert reaches the backend.","Test handshakes with openssl s_client including -cert/-key before shipping."],"tags":["mtls","authentication","certificates","security"],"backgroundTag":"no-client-certificate","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"}