Hi,

I now changed the implementation of option #1 to use separate SSLContext
instances in SSLContextAndOptions for client and server role. Each
SSLContext is initialized with standard PKIX managers from its own keystore
/ truststore. There is no custom key- or trust-manager. As far as I
understand, this should work in FIPS mode.
There is no change in config properties, and it is fully backward
compatible.

What are your thoughts?

Thanks,
Dávid

Dávid Paksy <[email protected]> ezt írta (időpont: 2026. aug. 17., H,
11:31):

> Hi Andor,
>
> Sorry, I was too quick to send my response. Probably you didn't meant the
> FIPS mode property in ZooKeeper but FIPS mode in Java.
>
> Enabling FIPS mode in Java imposes strict constraints on which KeyManager
> and TrustManager implementations can be instantiated and initialized.
> I looked into this and in FIPS mode, SSLContext.init() will throw an
> exception if custom manager instances are passed. Something like:
> java.security.KeyManagementException: FIPS mode: only SunJSSE
> TrustManagers may be used.
>
> I agree that this can be an issue for the custom KeyManager and
> TrustManager implementation as both custom classes get passed directly to
> SSLContext.init(). So this approach will not work in FIPS mode.
>
> I'll look into this more and come up with another proposal.
>
> Best Regards,
> Dávid
>
>
> Dávid Paksy <[email protected]> ezt írta (időpont: 2026. aug. 17., H,
> 10:20):
>
>> Hi Andor,
>>
>> Many thanks for your feedback.
>>
>> Hmm, very good question. As far as I understand, in FIPS mode, the
>> split-truststore routing should still function.
>>
>> The certificate routing in ClientServerX509TrustManager is still active
>> in FIPS mode.
>>
>> This class "sits above" the FIPS branching. It routes:
>> - checkServerTrusted -> client trust manager (validates remote server
>> certs)
>> - checkClientTrusted -> server trust manager (validates remote client
>> certs)
>>
>> Each inner trust manager is whatever createTrustManager() returns - in
>> FIPS mode that's the raw JDK PKIX trust manager instead of ZKTrustManager.
>> The routing itself is unaffected.
>>
>> Regarding EKU enforcement, there's no explicit EKU checking in
>> ZKTrustManager or ClientServerX509TrustManager.The JDK's built-in PKIX
>> validator enforces EKU constraints. So in FIPS mode, EKU validation should
>> work identically.
>>
>> Or do you think I'm missing something?
>>
>> Best Regards,
>> Dávid
>>
>> Andor Molnár <[email protected]> ezt írta (időpont: 2026. aug. 13., Cs,
>> 23:00):
>>
>>> 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