Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: No inheritance of broker TLS configs

...

Direct ZK access in #2 above is being addressed via the already-accepted KIP-455: Create an Administrative API for Replica Reassignment, and the direct access flag will be deprecated via KIP-555: Deprecate Direct Zookeeper access in Kafka Administrative Tools.  Therefore no changes are required here.

Direct ZK access in #3 has already been replaced via a --bootstrap-server flag and will be deprecated in the next release via KIP-555 as well. A comment in the code at https://github.com/apache/kafka/blob/trunk/core/src/main/scala/kafka/admin/ConfigCommand.scala#L65) indicates that connecting directly to ZooKeeper with this CLI tool is still a supported use case when configuration information needs to be bootstrapped into a ZooKeeper quorum prior to starting Kafka.  This is a very special use case for sure, but it does mean that accessing ZooKeeper directly via this CLI tool will be required, and passing TLS configuration to it in a secured way will be necessary.

There is an additional CLI tool that supports bootstrapping information into ZooKeeper besides ConfigCommand: kafka-acls.{bat,sh} (kafka.admin.AclCommand).  Accessing ZooKeeper directly via this CLI tool will also be required, and passing TLS configuration to it in a secured way will also be necessary.

Goals

...

Direct ZooKeeper access is the whole point of #4, of course, but the ZooKeeper project does not yet provide functionality to pass secured TLS configs to the underlying class that we invoke from this shell script – org.apache.zookeper.ZooKeeperMain – as described in 

Jira
serverASF JIRA
serverId5aa69414-a9e9-3523-82ec-879b028fb15b
keyZOOKEEPER-3689
.  We will need to add it.

kafka-acls

...

.{bat,sh}

...

 (kafka.admin.AclCommand) is an additional CLI tool not in the above list that supports bootstrapping information into ZooKeeper.  Direct ZooKeeper access has been deprecated in the ACLs CLI tool for some time, but it is still required for this special use case, and passing TLS configuration in a secured way will be necessary.

Goals

  • Harden/secure the configuration mechanism for Zookeeper TLS connectivity from:
    • Kafka Brokers (including from kafka.security.authorizer.AclAuthorizer if/when configured)
    • zookeeper-security-migration.sh
    • kafka-configs.{bat,sh} and kafka-acls.{bat,sh}
    • zookeeper-shell.{bat,sh}
  • Support client certificate authentication to ZooKeeper both with and without SASL authentication in ZK Security Migrator and the broker (when zookeeper.set.acl is true).
  • Add system tests to confirm the hardened/secured configuration for TLS connectivity to ZooKeeper
  • Add explicit Kafka documentation on how to configure TLS connectivity to ZooKeeper
  • Add a reference in the Kafka documentation to the ZooKeeper Quorum TLS configuration (https://zookeeper.apache.org/doc/r3.5.6/zookeeperAdmin.html#Communication+using+the+Netty+framework)

Out of Scope

  • Zookeeper-to-Zookeeper Quorum TLS system tests and in-depth documentation (the ZooKeeper project already has such tests and documentation)
  • Dynamic reconfiguration of ZooKeeper TLS configs

Public Interfaces

New Broker and AclAuthorizer Configurations

The below table contains the complete list of added configs.  All configs being added are optional Strings with no default value unless otherwise noted.  These values are potentially required to access ZooKeeper in the first place, so they are not dynamically reconfigurable (dynamic reconfiguration values are currently stored in ZooKeeper).  Sensitive values (e.g. those of type Password) can be encrypted as described in KIP-421: Automatically resolve external configurations.

As an example, these are some of the configs that will be introduced:

zookeeper.ssl.client.enable=true
zookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty
zookeeper.ssl.keystore.location=kafka.jks
zookeeper.ssl.keystore.password=test1234
zookeeper.ssl.truststore.location=truststore.jks
zookeeper.ssl.truststore.password=test1234

Every config can be prefixed with "authorizer." for the case when kafka.security.authorizer.AclAuthorizer connects via TLS to a ZooKeeper quorum separate from the one that Kafka is using – this specific use case will be identified in the configuration by explicitly setting authorizer.zookeeper.ssl.client.enable=true.  The same defaults (if any) described below will apply to the prefixed configs.

Config KeyDocumentation

zookeeper.ssl.client.enable

Optional Boolean, default=false

Set client to use TLS when connecting to ZooKeeper. When true, <code>zookeeper.clientCnxnSocket</code> must be set (typically to <code>org.apache.zookeeper.ClientCnxnSocketNetty</code>); other values to set may include <include list of all other properties below>
zookeeper.clientCnxnSocketTypically set to <code>org.apache.zookeeper.ClientCnxnSocketNetty</code> when using TLS connectivity to ZooKeeper
zookeeper.ssl.keystore.locationKeystore location

...

Out of Scope

  • Zookeeper-to-Zookeeper Quorum TLS system tests and in-depth documentation (the ZooKeeper project already has such tests and documentation)
  • Dynamic reconfiguration of ZooKeeper TLS configs

Public Interfaces

New Broker and AclAuthorizer Configurations

The below table contains the complete list of added configs.  All configs being added are optional Strings with no default value unless otherwise noted.  These values are potentially required to access ZooKeeper in the first place, so they are not dynamically reconfigurable (dynamic reconfiguration values are currently stored in ZooKeeper).  Sensitive values (e.g. those of type Password) can be encrypted as described in KIP-421: Automatically resolve external configurations.

As an example, these are some of the configs that will be introduced:

zookeeper.ssl.client.enable=true
zookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty
zookeeper.ssl.keystore.location=kafka.jks
zookeeper.ssl.keystore.password=test1234
zookeeper.ssl.truststore.location=truststore.jks
zookeeper.ssl.truststore.password=test1234

Every config can be prefixed with "authorizer." for the case when kafka.security.authorizer.AclAuthorizer connects via TLS to a ZooKeeper quorum separate from the one that Kafka is using – this specific use case will be identified in the configuration by explicitly setting authorizer.zookeeper.ssl.client.enable=true.  The same defaults (if any) described below will apply to the prefixed configs.

Config KeyDocumentation

zookeeper.ssl.client.enable

Optional Boolean, default=false

Set client to use TLS when connecting to ZooKeeper. When true, <code>zookeeper.clientCnxnSocket</code> must be set (typically to <code>org.apache.zookeeper.ClientCnxnSocketNetty</code>); other values to set may include <include list of all other properties below>
zookeeper.clientCnxnSocketTypically set to <code>org.apache.zookeeper.ClientCnxnSocketNetty</code> when using TLS connectivity to ZooKeeper
zookeeper.ssl.keystore.locationKeystore location when using a client-side certificate with TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.keyStore.location</code> system property (note the camelCase) and inherits the value of <code>ssl.keystore.location</code> if no explicit value is set both here and via the system property.

zookeeper.ssl.keystore.password

Optional Password

Keystore password when using a client-side certificate with TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.keyStore.password</code> system property (note the camelCase) and inherits the value of <code>ssl.keystore.password</code> if no explicit value is set both here and via the system property.

zookeeper.ssl.keystore.type

Keystore type when using a client-side certificate with TLS connectivity to ZooKeeper.  Overrides   Overrides any explicit value set via the <code>zookeeper.ssl.keyStore.type<location</code> system code> system property (note the camelCase) and inherits the value of <code>ssl.keystore.type</code> (and its default value if necessary) if no explicit value is set both here and via the system property.

zookeeper.ssl.keystore.password

Optional Password

Keystore password when using a client-side certificate with TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.keyStore.password</code> system property (note the camelCase).

zookeeper.ssl.

truststore

keystore.

location

type

Truststore location Keystore type when using a client-side certificate with TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.trustStorekeyStore.location<type</code> system property (note the camelCase) and inherits the The default value of <code>ssl.truststore.location</code> if no explicit value is set both here and via the system property<code>null</code> means the type will be auto-detected based on the filename extension of the keystore.
zookeeper.ssl.truststore.passwordlocationOptional PasswordTruststore password location when using TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.trustStore.password<location</code> system property (note the camelCase).
zookeeper.ssl.truststore.password

Optional Password

Truststore password when using TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.trustStore.password</code> system property (note the camelCase) and inherits the value of <code>ssl.truststore.password</code> if no explicit value is set both here and via the system property.

zookeeper.ssl.truststore.type

Truststore type when using TLS connectivity to ZooKeeper.  Overrides any explicit value set via the <code>zookeeper.ssl.trustStore.type</code> system property (note the camelCase) and inherits the .  The default value of <code>ssl.truststore.type</code> (and its default value if necessary) if no explicit value is set both here and via the system property<code>null</code> means the type will be auto-detected based on the filename extension of the truststore.

zookeeper.ssl.protocol

Default=TLSv1.2

Specifies the protocol to be used in ZooKeeper TLS negotiation.  Overrides any explicit value set via the <code>zookeeper.ssl.protocol</code> system property and inherits the value of <code>ssl.protocol</code> (and its default value if necessary) if no explicit value is set both here and via the system property.zookeeper.ssl.enabled.protocols.
zookeeper.ssl.enabled.protocolsSpecifies the enabled protocol(s) in ZooKeeper Specifies the enabled protocol(s) in ZooKeeper TLS negotiation (csv).  Overrides any explicit value set via the <code>zookeeper.ssl.enabledProtocols</code> system property (note the camelCase) and inherits The default value of <code>null</code> means the enabled protocol will be the value of <code>sslthe <code>zookeeper.enabledssl.protocols<protocol</code> (and its default value if necessary) if no explicit value is set both here and via the system configuration property.
zookeeper.ssl.cipher.suitesSpecifies the enabled cipher suites to be used in ZooKeeper TLS negotiation (csv).  Overrides any explicit value set via the <code>zookeeper.ssl.ciphersuites</code> system property (note the single word "ciphersuites") and inherits the .  The default value of <code>ssl.cipher.suites</code> (if any) if no explicit value is set both here and via the system property<code>null</code> means the list of enabled cipher suites is determined by the Java runtime being used.
zookeeper.ssl.context.supplier.classSpecifies the class to be used for creating SSL context in ZooKeeper TLS communication

zookeeper.ssl.endpoint.identification.algorithm

Default=https

Specifies whether to enable hostname verification in the ZooKeeper TLS negotiation process, with (case-insensitively) "https" meaning ZooKeeper hostname verification is enabled and an explicit blank value meaning it is disabled (disabling it is only recommended for testing purposes).  Overrides any explicit "true" or "false" value set via the <code>zookeeper.ssl.hostnameVerification</code> system property (true implying https and false implying blank) and inherits the value of <code>ssl.endpoint.identification.algorithm</code> (if any) if no explicit value or non-value is set both here and via the system property.

zookeeper.ssl.crl.enable

Optional Boolean, default=false

Specifies whether to enable Certificate Revocation List in the ZooKeeper TLS protocols

zookeeper.ssl.ocsp.enable

Optional Boolean, default=false

Specifies whether to enable Online Certificate Status Protocol in the ZooKeeper TLS protocols

...

  • New Kafka configurations, both non-prefixed as well as prefixed with "authorizer.", with existing Kafka configurations inherited as described.
  • A new --zk-tls-config-file parameter for:
    • ZooKeeper Security Migration Tool
    • Config Command CLI (for the special use case of bootstrapping TLS-enabled ZooKeeper)
    • ACL Command CLIs (for the special use case of bootstrapping TLS-enabled ZooKeeper)
  • A new -zk-tls-config-file parameter in the ZooKeeper Shell (again, note the single dash as opposed to the double-dash used above)

ZooKeeper supports Java system properties for configuration, and there are Kafka TLS configuration keys/values that are semantically equivalent to the ZooKeeper configurations in many case as well; this is described above, but for clarity it is also described as an evaluation algorithm for configuration values here:

  1. System properties define an initial value to be used.  For example, if the Java process is started with "-Dzookeeper.ssl.trustStore.location=/the/path" then that will be the starting value for the zookeeper.ssl.truststore.location configuration.  Note that the system properties use the ZooKeeper camelCase convention; this cannot be changed.
  2. Explicit configuration values take precedence over any value defined via a system property.  So if in addition to the above system property the configuration explicitly includes "zookeeper.ssl.truststore.location=/another/path" then that will be the value for the zookeeper.ssl.truststore.location configuration
  3. If no value exists at this point – no system property and no explicit value – then any explicit, equivalent Kafka configuration will be used.  So, for example, if no such system property in (1) or config in (2) existed but the same config file contained "ssl.truststore.location=/the/kafka/path" then that would be the value used.

The list of configs for which the above algorithm will be used is as follows (this is consistent with the configuration descriptions provided in the table above – it is presented here in this form for clarity):

...

The proposed changes also include the addition of:

  • System tests to confirm the hardened/secured configuration for TLS connectivity to ZooKeeper
  • The use of ZooKeeper Security Migrator and Kafka Brokers with client certificate authentication both with and without SASL
  • Explicit Kafka documentation on how to configure TLS connectivity to ZooKeeper

Compatibility, Deprecation, and Migration Plan

The changes are additions only, and there is no compatibility issue in the broker because the default for the broker config zookeeper.client.secure is false; TLS to ZooKeeper is an opt-in.

Test Plan

System tests will cover the following:

  • Migrating Zookeeper/Kafka clusters from non-TLS-enabled ZooKeeper to TLS-enabled ZooKeeper
  • Invoking the Zookeeper Security Migration tool against TLS-enabled ZooKeeper both with and without ZK SASL authentication enabled

Compatibility testing is unnecessary because Zookeeper TLS is not available in prior versions.

The connection between Kafka and Zookeeper is not on a critical path related to performance – brokers don't repeatedly communicate with Zookeeper as they process messages, for example – so introducing TLS encryption here does not require explicit performance testing.

Rejected Alternatives

ZooKeeper-Style Configuration Names

ZooKeeper uses camelCase configs that are inconsistent with Kafka broker configs:

ZooKeeper ConfigKafka Broker Config
zookeeper.ssl.keyStore.locationssl.keystore.location
zookeeper.ssl.keyStore.passwordssl.keystore.password
zookeeper.ssl.keyStore.typessl.keystore.type
zookeeper.ssl.trustStore.locationssl.truststore.location
zookeeper.ssl.trustStore.passwordssl.truststore.password
zookeeper.ssl.trustStore.typessl.truststore.type
zookeeper.ssl.ciphersuitesssl.cipher.suites
zookeeper.ssl.enabledProtocolsssl.enabled.protocols

It would be confusing and prone to mistake to have such a mismatch – especially for people who tend to know very little about ZooKeeper compared to Kafka.

The ZooKeeper config "zookeeper.client.secure" is also confusing – it only refers to whether the client should be configured to communicate with a TLS-encrypted ZK socket and has nothing to do with any other security-related client configuration that might be implied by the term "secure" (e.g. SASL, ACLs).  We therefore use the broker-side config "zookeeper.ssl.client.enable" instead.

Inheriting Broker Configuration Values

As mentioned above, certain broker configuration related to TLS cannot be inherited because keystore and trustore information is dynamically reconfigurable and may end up being stored in ZooKeeper.  There are other TLS configuration values that are not dynamically reconfigurable in the broker (protocols and cipher suites, for example), but selectively inheriting these values provides little value and would simply introduce confusion as people could assume – incorrectly – that keystore ad truststore information could also be inherited.  We therefore inherit nothing from the broker related to TLS configuration

Note that inheritance occurs on brokers and on CLI tools, and it also occurs for AclAuthorizer on the broker when it is explicitly pointed at a separate ZooKeeper quorum (with all explicit ZooKeeper configs in the second column starting with "authorizer.zookeeper."

The proposed changes also include the addition of:

  • System tests to confirm the hardened/secured configuration for TLS connectivity to ZooKeeper
  • The use of ZooKeeper Security Migrator and Kafka Brokers with client certificate authentication both with and without SASL
  • Explicit Kafka documentation on how to configure TLS connectivity to ZooKeeper

Compatibility, Deprecation, and Migration Plan

The changes are additions only, and there is no compatibility issue in the broker because the default for the broker config zookeeper.client.secure is false. TLS to ZooKeeper is an opt-in even when TLS is enabled between brokers because zookeeper.client.secure doesn't inherit its value from anywhere and defaults to false unless explicitly set to true

Test Plan

System tests will cover the following:

  • Migrating Zookeeper/Kafka clusters from non-TLS-enabled ZooKeeper to TLS-enabled ZooKeeper
  • Invoking the Zookeeper Security Migration tool against TLS-enabled ZooKeeper both with and without ZK SASL authentication enabled

Compatibility testing is unnecessary because Zookeeper TLS is not available in prior versions.

The connection between Kafka and Zookeeper is not on a critical path related to performance – brokers don't repeatedly communicate with Zookeeper as they process messages, for example – so introducing TLS encryption here does not require explicit performance testing.

Rejected Alternatives

Direct ZooKeeper Configs

ZooKeeper uses camelCase configs that are inconsistent with Kafka broker configs:

...

It would be confusing and prone to mistake to have such a mismatch – especially for people who tend to know very little about ZooKeeper compared to Kafka.

The ZooKeeper config "zookeeper.client.secure" is also confusing – it only refers to whether the client should be configured to communicate with a TLS-encrypted ZK socket and has nothing to do with any other security-related client configuration that might be implied by the term "secure" (e.g. SASL, ACLs).  We therefore use the broker-side config "zookeeper.ssl.client.enable" instead.