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

Reply via email to