SASL Authentication
Docker
Zookeeper
Kafka
Cybersecurity

SASL authentication in docker zookeeper and kafka

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When Kafka runs with ZooKeeper in Docker, SASL setup usually has two separate authentication paths: Kafka clients and brokers talking to Kafka, and Kafka brokers talking to ZooKeeper. Most failed setups happen because only one of those paths is configured.

Start With The Architecture

In a ZooKeeper-based Kafka deployment, you typically need to think about:

  • client to broker authentication
  • broker to broker authentication
  • broker to ZooKeeper authentication

These are related, but they are not the same configuration block.

If you configure only the Kafka listener for SASL and ignore the broker's ZooKeeper client login, the broker may fail to start or fail to register correctly.

A Common Simple Choice: PLAIN For Kafka And Digest For ZooKeeper

For demos and internal environments, a common pattern is:

  • Kafka listener uses SASL_PLAINTEXT with PLAIN
  • ZooKeeper uses SASL with digest-based credentials

This keeps the example understandable. In a real untrusted network, use TLS as well, because PLAIN without TLS protects authentication logic but not wire confidentiality.

Kafka Broker Configuration

A minimal Kafka server configuration usually includes:

properties
1listeners=SASL_PLAINTEXT://:9092
2advertised.listeners=SASL_PLAINTEXT://kafka:9092
3security.inter.broker.protocol=SASL_PLAINTEXT
4sasl.enabled.mechanisms=PLAIN
5sasl.mechanism.inter.broker.protocol=PLAIN
6zookeeper.sasl.client=true

This says:

  • Kafka accepts SASL-authenticated client connections
  • brokers use SASL when talking to each other
  • the broker acts as a SASL client when connecting to ZooKeeper

Kafka JAAS File

The Kafka process typically needs a JAAS file containing both the Kafka server login section and the ZooKeeper client login section.

properties
1KafkaServer {
2  org.apache.kafka.common.security.plain.PlainLoginModule required
3  username="broker"
4  password="broker-secret"
5  user_broker="broker-secret"
6  user_app="app-secret";
7};
8
9Client {
10  org.apache.zookeeper.server.auth.DigestLoginModule required
11  username="zkuser"
12  password="zk-secret";
13};

The KafkaServer section is used for broker-side Kafka authentication. The Client section is used by Kafka when it connects to ZooKeeper.

ZooKeeper Configuration

ZooKeeper must also be told to use SASL authentication.

A typical configuration includes:

properties
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
requireClientAuthScheme=sasl

And its JAAS file might look like this:

properties
1Server {
2  org.apache.zookeeper.server.auth.DigestLoginModule required
3  user_zkuser="zk-secret";
4};

Now the broker's ZooKeeper client credentials can actually be validated by the ZooKeeper server.

A Docker Compose Sketch

Different images use different environment variable names, so the exact wiring varies. But the overall shape usually looks like this:

yaml
1services:
2  zookeeper:
3    image: confluentinc/cp-zookeeper:latest
4    environment:
5      ZOOKEEPER_CLIENT_PORT: 2181
6      KAFKA_OPTS: "-Djava.security.auth.login.config=/etc/kafka/zookeeper_jaas.conf"
7    volumes:
8      - ./zookeeper_jaas.conf:/etc/kafka/zookeeper_jaas.conf:ro
9      - ./zookeeper.properties:/etc/kafka/zookeeper.properties:ro
10
11  kafka:
12    image: confluentinc/cp-kafka:latest
13    depends_on:
14      - zookeeper
15    environment:
16      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
17      KAFKA_OPTS: "-Djava.security.auth.login.config=/etc/kafka/kafka_jaas.conf"
18    volumes:
19      - ./kafka_jaas.conf:/etc/kafka/kafka_jaas.conf:ro
20      - ./server.properties:/etc/kafka/server.properties:ro

The exact startup command and property injection depend on the image, but the pattern stays the same: mount config files and point the JVM to the JAAS file.

Client Configuration

A Kafka client also needs matching SASL settings.

properties
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="app" password="app-secret";

If the broker accepts PLAIN and the client sends no SASL config, authentication fails even though the network path is open.

A Modern Caveat

ZooKeeper-based Kafka is legacy architecture. Modern Kafka deployments increasingly use KRaft mode instead of ZooKeeper. If you are building a new cluster, check whether you actually need the ZooKeeper path at all.

But if you are maintaining an existing ZooKeeper-based deployment, the two-plane authentication model described here is still the right way to think about it.

Common Pitfalls

The most common mistake is configuring SASL for Kafka listeners but forgetting the broker's SASL client configuration for ZooKeeper.

Another mistake is using PLAIN without TLS on networks where credentials should not travel in clear text.

Developers also assume all Docker images use the same config paths and environment variables. They do not, so adapt the volume mounts and JVM flags to the chosen image.

Finally, if JAAS section names do not match what the process expects, the files can be mounted correctly and still fail at runtime.

Summary

  • In ZooKeeper-based Kafka, secure the Kafka side and the ZooKeeper side separately.
  • Kafka brokers often need both KafkaServer and ZooKeeper Client JAAS sections.
  • ZooKeeper must be configured to require SASL as well.
  • Client settings must match the broker's SASL listener configuration.
  • For new deployments, consider whether KRaft removes the need for ZooKeeper-specific setup entirely.

Course illustration
Course illustration

All Rights Reserved.