kubernetes/kops · error

failed to verify client certificate chain: %w

Error message

failed to verify client certificate chain: %w

What it means

AuthenticateClientToUniverse validates an mTLS client certificate against the universe's CA. The certificate chain verification via crypto/x509 Cert.Verify failed, so the client's certificate cannot be trusted as issued by the universe CA. The underlying x509 error (unknown authority, expired, etc.) is wrapped with %w.

Source

Thrown at discovery/pkg/discovery/auth.go:66

		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 {
				opts.Intermediates.AddCert(peerCertificates[i])
			}
		}

		chains, err := peerCertificates[0].Verify(opts)
		if err != nil {
			return nil, fmt.Errorf("failed to verify client certificate chain: %w", err)
		}
		verifiedChains = chains
	}

	// The universe ID must match at least one of the certificates in the chain (typically the root CA).
	var matchingChain []*x509.Certificate
	for _, verifiedChain := range verifiedChains {
		for _, cert := range verifiedChain {
			hash := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
			calculatedUniverseID := hex.EncodeToString(hash[:])
			if calculatedUniverseID == universeID {
				matchingChain = verifiedChain
				break
			}
		}
	}

	if matchingChain == nil {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Regenerate the client certificate signed by the universe's CA.
  2. Ensure the client sends its full chain (leaf + intermediates) during the TLS handshake.
  3. Check certificate expiry (openssl x509 -noout -dates) and renew if expired.
  4. Confirm the server's trust pool (RootCAs in opts) contains the universe root CA that actually signed the client cert.

Example fix

// before: client presents only the leaf cert
conn cert = leaf
// after: client loads the full chain
tls.LoadX509KeyPair("client.crt", "client.key")
tlsConfig.Certificates[0] = tls.Certificate{Certificate: append([][]byte{leafDER}, intermediates...)}
Defensive patterns

Strategy: validation

Validate before calling

// verify the client cert before presenting it
leaf, _ := x509.ParseCertificate(certDER)
opts := x509.VerifyOptions{Roots: universeCAPool, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}}
if _, err := leaf.Verify(opts); err != nil {
	return fmt.Errorf("client cert will not verify against universe CA: %w", err)
}

Type guard

func hasValidClientCert(leaf *x509.Certificate, roots *x509.CertPool) bool {
	_, err := leaf.Verify(x509.VerifyOptions{Roots: roots, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}})
	return err == nil
}

Prevention

When it happens

Trigger: Calling AuthenticateClientToUniverse with a TLS peer whose leaf certificate fails x509.Verify: signed by an unknown CA, expired/not-yet-valid, wrong key usage, or intermediates not supplied in peerCertificates.

Common situations: Client presents a cert from a different universe/CA than the server trusts; expired client certificate; missing intermediate certs in the TLS handshake; incorrect RootCAs pool loaded in verification opts.

Understand the failure class

Related errors


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