kubernetes/kops · error
no client certificate presented
Error message
no client certificate presented
What it means
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.
Source
Thrown at discovery/pkg/discovery/auth.go:41
"fmt"
"net/http"
)
type UserInfo struct {
UniverseID string
ClientID string
}
// AuthenticateClientToUniverse extracts the Universe ID and Client ID from the mTLS connection.
// The Universe ID is defined as the SHA256 hash of the root CA certificate (DER bytes)
// presented in the client's certificate chain.
// The Client ID is taken from the Common Name (CN) of the leaf certificate.
func AuthenticateClientToUniverse(r *http.Request, universeID string) (*UserInfo, error) {
if r.TLS == nil {
return nil, fmt.Errorf("no TLS connection")
}
if len(r.TLS.PeerCertificates) == 0 {
return nil, fmt.Errorf("no client certificate presented")
}
// Verify the chain is valid, though we don't validate that the CA certificate is trusted.
var verifiedChains [][]*x509.Certificate
{
peerCertificates := r.TLS.PeerCertificates
opts := x509.VerifyOptions{
Roots: x509.NewCertPool(),
Intermediates: x509.NewCertPool(),
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
for i := 1; i < len(peerCertificates); i++ {
if i == len(peerCertificates)-1 {
// Last cert is the root
opts.Roots.AddCert(peerCertificates[i])
} else {View on GitHub (pinned to 4c8573c808)
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.
Example fix
// before
cfg := &tls.Config{ClientCAs: caPool} // client certs requested but not required
// after
cfg := &tls.Config{ClientCAs: caPool, ClientAuth: tls.RequireAndVerifyClientCert} Defensive patterns
Strategy: validation
Validate before calling
// enforce client certs at server startup
cfg := &tls.Config{
ClientCAs: caPool,
ClientAuth: tls.RequireAndVerifyClientCert,
}
server := &http.Server{Addr: ":443", TLSConfig: cfg} Type guard
func hasClientCert(r *http.Request) bool {
return r.TLS != nil && len(r.TLS.PeerCertificates) > 0
} Try / catch
// Go: reject missing client certs with 401
u, err := AuthenticateClientToUniverse(r, universeID)
if err != nil {
http.Error(w, "client certificate required", http.StatusUnauthorized)
return
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- no TLS connection
- error reading client keypair: %v
- failed to verify client certificate chain: %w
- DIGITALOCEAN_ACCESS_TOKEN is required
- DIGITALOCEAN_ACCESS_TOKEN is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/7ffc7fa8d47a5665.
Report an issue: GitHub.