Hi David, Option #1
You mentioned a custom ZooKeeper trustmanager implementation which picks the right certificate for client/server validation. How would it work in FIPS mode when we don’t use custom trustmanagers, but rely on JDK implementation? Apart from this I tend to support this option. Sounds more secure and it could include a fallback mechanism to Option #2 if only one keystore is specified in the config. Andor > On Aug 12, 2026, at 10:44, Dávid Paksy <[email protected]> wrote: > > Hi All, > > I’d like to start a discussion to improve public Certificate Authorities > (CA) compatibility. Industry standards and public CA-s (like DigiCert) are > sunsetting multi-use certificates, making the current requirement for dual > serverAuth and clientAuth Extended Key Usages (EKUs) difficult to manage. > > ZooKeeper currently only supports dual-purpose certificates (or no EKU > extension at all which means unconstrained). These certificates carry both > the serverAuth and clientAuth EKUs, meaning the same key and certificate is > used whether the service running on the host is acting as a TLS server or > as a client in a mutual-TLS (mTLS) handshake. > In a ZooKeeper quorum cluster, every node acts as both TLS client and > server to its peers, making the single-EKU question especially relevant for > inter-node communication. > > In order to support single EKU certs I see the following two possible > options. > > 1. **Separate keystore / truststore files for client and server TLS roles** > > This requires new config properties (under "ssl." and "ssl.quorum." > prefixes): > - client.keyStore.{location,password,passwordPath,type} > - server.trustStore.{location,password,passwordPath,type} > > For code changes we could introduce new X509ExtendedKeyManager and > X509ExtendedTrustManager implementations: > - ClientServerX509KeyManager - routes chooseServerAlias() to the server > keystore and chooseClientAlias() to a dedicated client keystore > - ClientServerX509TrustManager - routes checkClientTrusted() (validating > incoming client certs when acting as server) to a dedicated server-role > truststore, and checkServerTrusted() (validating remote server certs when > acting as client) to the default truststore > > If the new properties are absent, we fall back to the existing shared > keystore / truststore (to be fully backward compatible). > > This approach would give independent trust chains and better > least-privilege in hardened environments - file permissions can restrict > which process/role accesses which key, however this means more files per > node and more config properties to set. > > I filed ZOOKEEPER-5070 for this and have a draft PR there. > > --- > > 2. **Single keystore with different alias for the client and server roles** > > We use the PKIX KeyManagerFactory which performs EKU-aware alias selection. > Here we might not need code change. But this way we are relying on JDK > implementation behavior that isn't formally specified in the > KeyManagerFactory API contract; may differ across JDK vendors (IBM Semeru, > Azul, GraalVM). > > However Trust side has no equivalent auto-routing — the TrustManager uses > one truststore for both checkClientTrusted() and checkServerTrusted(). We > cannot use different CAs for client-facing vs quorum communication. > > This approach would mean fewer files, simpler deployment but principle of > least privilege is weaker - a compromised process always has both keys. > > --- > > This single EKU topic is also being discussed on the Apache Kafka developer > mailing list and they tend to favor option #2 (Single keystore with > different aliases): > https://lists.apache.org/[email protected]:lte=1M:eku > > > What are your thoughts on these? > Any experience using single EKU certificates with ZooKeeper? > Do you see more possible options? > > Best Regards, > Dávid
