Kafka Security: SSL, SASL & ACL Authorization
Out of the box, Kafka transmits data in plaintext and accepts connections from anyone. In production you need three layers: encryption (SSL/TLS) to protect data in transit, authentication (SASL) to verify client identity, and authorization (ACLs) to control which clients can produce or consume which topics.
Contents
SSL/TLS Overview
SSL provides two things: encryption (all bytes on the wire are ciphertext) and optional mutual authentication (both broker and client present certificates). You need a keystore on each broker and a truststore on each client.
/*
Key concepts:
─────────────────────────────────────────────────────
Keystore — contains a private key + certificate
(used by the holder to prove identity)
Truststore — contains trusted CA certificates
(used to verify the other party's cert)
One-way SSL — only the broker has a certificate;
clients trust the broker CA.
Mutual TLS (mTLS) — both broker and client present
certificates to each other.
─────────────────────────────────────────────────────
*/
Broker SSL Configuration
Generate a broker keystore with keytool9093
# 1. Generate a CA key and certificate
openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 -subj "/CN=kafka-ca"
# 2. Create broker keystore
keytool -keystore kafka.broker.keystore.jks -alias broker -validity 365 \
-genkey -keyalg RSA -dname "CN=kafka-broker"
# 3. Sign the broker certificate with the CA
keytool -keystore kafka.broker.keystore.jks -alias broker -certreq -file broker-cert-request
openssl x509 -req -CA ca-cert -CAkey ca-key -in broker-cert-request \
-out broker-cert-signed -days 365 -CAcreateserial
# 4. Import CA + signed cert into keystore
keytool -keystore kafka.broker.keystore.jks -alias CARoot -import -file ca-cert
keytool -keystore kafka.broker.keystore.jks -alias broker -import -file broker-cert-signed
# 5. Create truststore containing the CA
keytool -keystore kafka.broker.truststore.jks -alias CARoot -import -file ca-cert
# server.properties — broker config
listeners=PLAINTEXT://localhost:9092,SSL://localhost:9093
advertised.listeners=PLAINTEXT://localhost:9092,SSL://localhost:9093
ssl.keystore.location=/etc/kafka/ssl/kafka.broker.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/etc/kafka/ssl/kafka.broker.truststore.jks
ssl.truststore.password=truststore-password
# Require client certificates (mTLS)
ssl.client.auth=required
Client SSL Configuration
Clients (producers and consumers) need a truststore containing the CA that signed the broker certificate. For mTLS they also need their own keystore.
Properties props = new Properties();
props.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "localhost:9093");
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SSL");
// Client truststore — trust the broker's CA
props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, "/etc/kafka/ssl/client.truststore.jks");
props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "truststore-password");
// Client keystore — for mTLS (present own certificate to broker)
props.put(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG, "/etc/kafka/ssl/client.keystore.jks");
props.put(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, "keystore-password");
props.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, "key-password");
// Serializers …
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
SASL/PLAIN Authentication
SASL/PLAIN sends username and password. Use it only over SSL, without encryption the credentials are transmitted in cleartext.
# server.properties — enable SASL_SSL listener
listeners=SASL_SSL://localhost:9094
advertised.listeners=SASL_SSL://localhost:9094
security.inter.broker.protocol=SASL_SSL
sasl.mechanism.inter.broker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN
# JAAS config file path (or inline with listener.name prefix)
listener.name.sasl_ssl.plain.sasl.jaas.config=\
org.apache.kafka.common.security.plain.PlainLoginModule required \
username="admin" password="admin-secret" \
user_admin="admin-secret" \
user_producer="producer-secret" \
user_consumer="consumer-secret";
// Client SASL/PLAIN config
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
props.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
props.put(SaslConfigs.SASL_JAAS_CONFIG,
"org.apache.kafka.common.security.plain.PlainLoginModule required " +
"username=\"producer\" password=\"producer-secret\";");
// SSL truststore config (same as above) …
SASL/SCRAM Authentication
SCRAM stores credential hashes in Kafka metadata. Create users with the kafka-configs.sh
# Create a SCRAM-SHA-512 credential for user 'alice'
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --add-config 'SCRAM-SHA-512=[iterations=8192,password=alice-password]' \
--entity-type users --entity-name alice
# List all users
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--describe --entity-type users
# server.properties
sasl.enabled.mechanisms=SCRAM-SHA-512
listener.name.sasl_ssl.scram-sha-512.sasl.jaas.config=\
org.apache.kafka.common.security.scram.ScramLoginModule required;
// Client SCRAM config
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
props.put(SaslConfigs.SASL_MECHANISM, "SCRAM-SHA-512");
props.put(SaslConfigs.SASL_JAAS_CONFIG,
"org.apache.kafka.common.security.scram.ScramLoginModule required " +
"username=\"alice\" password=\"alice-password\";");
ACL Authorization
Kafka's built-in ACL authorizer controls which principals (users) can perform which operations on which resources (topics, consumer groups, cluster).
# Enable ACL authorizer in server.properties
# authorizer.class.name=kafka.security.authorizer.AclAuthorizer
# super.users=User:admin
# Grant alice WRITE on topic 'orders'
bin/kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:alice \
--operation Write --topic orders
# Grant bob READ on topic 'orders' and on consumer group 'bob-group'
bin/kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:bob \
--operation Read --topic orders
bin/kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:bob \
--operation Read --group bob-group
# List all ACLs
bin/kafka-acls.sh --bootstrap-server localhost:9092 --list
Spring Boot Security Config
Configure SSL and SASL in application.properties
spring.kafka.bootstrap-servers=localhost:9094
spring.kafka.security.protocol=SASL_SSL
# SASL
spring.kafka.properties.sasl.mechanism=SCRAM-SHA-512
spring.kafka.properties.sasl.jaas.config=\
org.apache.kafka.common.security.scram.ScramLoginModule required \
username="alice" password="alice-password";
# SSL truststore
spring.kafka.ssl.trust-store-location=classpath:client.truststore.jks
spring.kafka.ssl.trust-store-password=truststore-password
# Optional: client certificate for mTLS
spring.kafka.ssl.key-store-location=classpath:client.keystore.jks
spring.kafka.ssl.key-store-password=keystore-password
spring.kafka.ssl.key-password=key-password