{"record":{"id":"8142c9879e03cd8c","repo":"kubernetes/kops","slug":"client-certificate-chain-does-not-match-universe-i","errorCode":null,"errorMessage":"client certificate chain does not match universe ID","messagePattern":"client certificate chain does not match universe ID","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/pkg/discovery/auth.go","lineNumber":85,"sourceCode":"\t\t}\n\t\tverifiedChains = chains\n\t}\n\n\t// The universe ID must match at least one of the certificates in the chain (typically the root CA).\n\tvar matchingChain []*x509.Certificate\n\tfor _, verifiedChain := range verifiedChains {\n\t\tfor _, cert := range verifiedChain {\n\t\t\thash := sha256.Sum256(cert.RawSubjectPublicKeyInfo)\n\t\t\tcalculatedUniverseID := hex.EncodeToString(hash[:])\n\t\t\tif calculatedUniverseID == universeID {\n\t\t\t\tmatchingChain = verifiedChain\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif matchingChain == nil {\n\t\treturn nil, fmt.Errorf(\"client certificate chain does not match universe ID\")\n\t}\n\n\tclientID := matchingChain[0].Subject.CommonName\n\tif clientID == \"\" {\n\t\treturn nil, fmt.Errorf(\"client certificate missing Common Name\")\n\t}\n\n\treturn &UserInfo{\n\t\tUniverseID: universeID,\n\t\tClientID:   clientID,\n\t}, nil\n}\n","sourceCodeStart":67,"sourceCodeEnd":98,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/auth.go#L67-L98","documentation":"After the cert chain verifies cryptographically, AuthenticateClientToUniverse requires the universe ID to match at least one certificate in the verified chain (typically the root CA). No chain contained a certificate whose identity equals the universe ID, so the client is not a member of this universe and authentication is rejected.","triggerScenarios":"Calling AuthenticateClientToUniverse with a certificate chain that verifies against a valid CA but whose chain contains no certificate matching the expected universeID (e.g. wrong universe's cert presented).","commonSituations":"Client configured with credentials from a different cluster/universe; server's expected universeID changed after a re-provision; stale or copied kubeconfig/cert bundle pointing at another universe.","solutions":["Issue the client a certificate signed by the CA whose identity (subject) matches the target universeID.","Verify the universeID passed to AuthenticateClientToUniverse matches the universe the cert was issued for.","Re-provision or re-issue client credentials after a universe/cluster rebuild so the root CA matches."],"exampleFix":"// before: cert from universe-a presented to universe-b\nAuthenticateClientToUniverse(ctx, universeBID, tlsConn)\n// after: use credentials issued for the target universe\nAuthenticateClientToUniverse(ctx, universeBID, connWithUniverseBCert)","handlingStrategy":"validation","validationCode":"func certMatchesUniverse(chain []*x509.Certificate, universeID string) bool {\n\tfor _, c := range chain {\n\t\tif c.Subject.CommonName == universeID || c.Subject.Organization[0] == universeID {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n// call before authenticating\nif !certMatchesUniverse(peerCertificates, universeID) { /* reject early */ }","typeGuard":"func isUniverseCert(cert *x509.Certificate, universeID string) bool {\n\treturn cert != nil && (cert.Subject.CommonName == universeID || slices.Contains(cert.Subject.Organization, universeID))\n}","tryCatchPattern":null,"preventionTips":["Store per-universe credential bundles separately and load the one matching the target universe.","Regenerate credentials after any universe/cluster rebuild.","Log the cert issuer/subject on auth failure for fast diagnosis."],"tags":["mtls","authorization","certificate","identity"],"backgroundTag":"certificate-universe-mismatch","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"}