PRACTITIONER GUIDE | CLOUD SECURITY
Practitioner GuideUpdated 13 min read

Apache Kafka Security Hardening: TLS, SASL Authentication, and ACLs

PLAINTEXT
Default Kafka listener protocol -- transmits all event data, credentials, and metadata in unencrypted plaintext
SASL_SSL
Recommended Kafka listener security protocol combining SASL authentication with TLS encryption for production deployments
3
Kafka ACL operation types most commonly needed: Read (consume), Write (produce), and Describe (metadata) -- grant only what each client needs
KRaft
Kafka's ZooKeeper-free consensus protocol since Kafka 3.3 -- eliminates ZooKeeper's separate security configuration surface

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Kafka's default configuration prioritizes ease of setup over security: no encryption, no authentication, no authorization. Every producer and consumer on the network can access every topic. In production environments handling financial events, user activity, or PII, this is an unacceptable risk. The good news is that Kafka's security model is well-designed -- TLS, SASL, and ACLs are all stable, production-tested features. The challenge is that configuring all three correctly requires coordinating broker configuration, client configuration, and credential management simultaneously. This guide covers the complete configuration path from insecure defaults to a production-hardened Kafka cluster.

Configure TLS Encryption on All Listeners

TLS encrypts all data in transit between brokers and between brokers and clients. Configure it before adding SASL authentication so you can verify TLS independently.

Generate broker keystores and a shared truststore

Create a CA: `openssl req -new -x509 -keyout ca-key -out ca-cert -days 3650`. For each broker, generate a keystore: `keytool -keystore kafka.broker-<n>.keystore.jks -alias broker-<n> -genkey -keyalg RSA`. Sign the broker certificate with the CA and import both the CA cert and signed broker cert into the keystore. Create a shared truststore containing the CA cert that all brokers and clients import: `keytool -keystore kafka.client.truststore.jks -importcert -alias CARoot -file ca-cert`.

Configure SSL listener in server.properties

In each broker's `server.properties`, change the listener to SSL: `listeners=SSL://broker-<n>:9093`. Add the keystore and truststore config: `ssl.keystore.location=/etc/kafka/ssl/kafka.broker.keystore.jks`, `ssl.keystore.password=<password>`, `ssl.truststore.location=/etc/kafka/ssl/kafka.client.truststore.jks`, `ssl.truststore.password=<password>`, `ssl.client.auth=required` (for mTLS) or `ssl.client.auth=none` (TLS encryption only, SASL handles auth). Set `ssl.endpoint.identification.algorithm=https` to enforce hostname verification on all connections.

Configure clients to use TLS

Update client `producer.properties` and `consumer.properties`: `security.protocol=SSL`, `ssl.truststore.location=/etc/kafka/ssl/kafka.client.truststore.jks`, `ssl.truststore.password=<password>`. For mTLS clients, also provide a client keystore. Test connectivity: `kafka-topics.sh --bootstrap-server broker:9093 --command-config client.properties --list` should connect and list topics.

Implement SASL/SCRAM-SHA-512 Authentication

SASL/SCRAM provides password-based authentication where credentials are stored as salted hashes and passwords are never transmitted in plaintext even over the SASL channel.

Create SCRAM credentials for each client principal

Create credentials using the Kafka CLI: `kafka-configs.sh --bootstrap-server broker:9092 --alter --add-config 'SCRAM-SHA-512=[iterations=8192,password=<password>]' --entity-type users --entity-name <username>`. Do this for each producer, consumer, and admin principal. Store the plaintext passwords in a secrets manager (Vault, AWS Secrets Manager) -- the Kafka broker stores only the SCRAM hash, not the plaintext.

Configure SASL/SCRAM on brokers

Add to `server.properties`: `security.inter.broker.protocol=SASL_SSL`, `sasl.mechanism.inter.broker.protocol=SCRAM-SHA-512`, `sasl.enabled.mechanisms=SCRAM-SHA-512`. Create a JAAS config file `/etc/kafka/kafka_server_jaas.conf` with the broker's own SCRAM credentials for inter-broker authentication. Set the JVM option: `-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf`. Change the listener: `listeners=SASL_SSL://broker:9093`, `listener.security.protocol.map=SASL_SSL:SASL_SSL`.

Configure SASL on clients

Update client properties: `security.protocol=SASL_SSL`, `sasl.mechanism=SCRAM-SHA-512`, `sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="<user>" password="<password>";`. Retrieve the password from your secrets manager at runtime rather than hardcoding it -- use a wrapper script or secrets injection to populate the JAAS config with the runtime credential.

Rotate SCRAM credentials without downtime

SCRAM credentials can be updated without broker restart: `kafka-configs.sh --alter --add-config 'SCRAM-SHA-512=[password=<new-password>]' --entity-type users --entity-name <username>`. The new credential takes effect immediately. Coordinate client rotation: update the client's JAAS config to the new password and restart the client. The broker accepts both old and new SCRAM credentials briefly during the rotation window because SCRAM negotiation is per-connection.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Configure Kafka ACLs for Topic Authorization

ACLs restrict which authenticated principals can produce to, consume from, or manage specific topics. Enable the authorizer before writing ACLs, but pre-populate ACLs first to avoid locking out existing clients.

Enable the authorizer

Add to `server.properties`: `authorizer.class.name=kafka.security.authorizer.AclAuthorizer` and `allow.everyone.if.no.acl.found=false`. The second property is critical -- setting it to false means any authenticated principal without a specific ACL is denied. Set it to true initially to audit ACL gaps without breaking existing clients, then switch to false once all legitimate principals have ACLs.

Grant producer ACLs

For each producer service, grant Write and Describe on its topics: `kafka-acls.sh --bootstrap-server broker:9093 --command-config admin.properties --add --allow-principal User:producer-service --operation Write --operation Describe --topic events-topic`. Scope ACLs to specific topic names rather than using the `--resource-pattern-type prefixed` wildcard unless multiple topics share a predictable prefix with the same authorization requirements.

Grant consumer ACLs including consumer group access

Consumers need Read on the topic AND Read on their consumer group: `kafka-acls.sh --add --allow-principal User:consumer-service --operation Read --topic events-topic --command-config admin.properties --bootstrap-server broker:9093` and separately `kafka-acls.sh --add --allow-principal User:consumer-service --operation Read --group consumer-group-name`. A common mistake is granting topic access but forgetting consumer group access, resulting in authorization errors at consumer startup.

The bottom line

Kafka security requires configuring three independent layers correctly: TLS for encryption, SASL/SCRAM for authentication, and ACLs for authorization. Each layer can be added incrementally -- start with TLS, validate it works, add SASL with allow.everyone.if.no.acl.found=true, validate all clients authenticate, then populate ACLs and flip to deny-by-default. Attempting to configure all three simultaneously on a production cluster is the most common cause of Kafka security configuration outages.

Frequently asked questions

What is the difference between SASL/PLAIN, SASL/SCRAM, and mTLS for Kafka client authentication?

SASL/PLAIN transmits credentials in cleartext over the SASL channel (though TLS encrypts the transport) -- credentials are stored in cleartext in the Kafka configuration. SASL/SCRAM-SHA-512 uses a challenge-response protocol that never transmits the actual password and stores credentials as salted hashes in ZooKeeper or KRaft metadata. mTLS (mutual TLS) uses client certificates for authentication -- no passwords, and clients are authenticated by certificate identity. For production, SASL/SCRAM-SHA-512 is the pragmatic choice; mTLS is preferred for internal service-to-service communication where certificate management is already in place.

How do Kafka ACLs work and what is the default authorization behavior?

Kafka ACLs are per-principal allow/deny rules stored in ZooKeeper or KRaft metadata. Each ACL specifies: principal (User:alice, Group:producers), operation (Read, Write, Create, Describe, Delete, Alter), resource type (Topic, Group, Cluster, TransactionalId), resource name (exact or prefixed), and host (IP restriction or * for any). When the SimpleAclAuthorizer is enabled, authenticated principals without any ACL entry are denied by default. Without an authorizer enabled (the default), all authenticated clients can access all resources -- enabling the authorizer without pre-populating ACLs will lock out all clients.

How do you configure multiple listeners for internal and external traffic?

Configure separate listeners for broker-to-broker and client-to-broker traffic. In `server.properties`: `listeners=BROKER://0.0.0.0:9091,CLIENT://0.0.0.0:9092` with `listener.security.protocol.map=BROKER:SASL_SSL,CLIENT:SASL_SSL` and `inter.broker.listener.name=BROKER`. This isolates internal replication traffic from client traffic, allows different authentication mechanisms per listener (mTLS for brokers, SCRAM for clients), and makes firewall rules cleaner -- clients connect on 9092, brokers on 9091, and you can restrict 9091 to broker IPs only.

How do you rotate Kafka TLS certificates without downtime?

Add the new certificate to the broker truststore before the old certificate expires: `keytool -importcert -keystore server.truststore.jks -alias new-ca -file new-ca.crt`. Kafka reads the truststore at connection establishment, not at startup, so adding a new CA to the truststore takes effect for new connections without a broker restart. Rotate the broker keystore (the server's own certificate) by updating the keystore file and triggering a rolling broker restart -- one broker at a time, allowing the cluster to rebalance partitions between restarts.

What security considerations apply specifically to KRaft mode vs ZooKeeper mode?

KRaft mode (Kafka without ZooKeeper) eliminates ZooKeeper's separate security surface: no more ZooKeeper TLS configuration, ZooKeeper ACLs, or ZooKeeper port exposure. In KRaft mode, controller-to-broker communication uses Kafka's own SASL/TLS stack. SCRAM credentials are stored in KRaft metadata logs rather than ZooKeeper znodes. The controller quorum voter configuration (`controller.quorum.voters`) requires careful security: controller nodes should be in a separate network segment from brokers and clients, and the controller listener should be restricted to broker IP ranges.

How should you secure Schema Registry in a Kafka deployment?

Confluent Schema Registry exposes an HTTP REST API for schema management. Secure it with: TLS for the HTTP listener (`listeners=https://0.0.0.0:8081`), mutual TLS or basic authentication for API access (`authentication.method=BASIC`), and IP-based access control restricting Schema Registry to the Kafka broker and client subnets. For Confluent Platform, enable RBAC to restrict which users can register, read, or delete schemas -- a misconfigured Schema Registry that allows public write access lets attackers inject malicious schemas that break consumer deserialization.

How do you audit Kafka access and detect unauthorized consumption?

Enable Kafka authorizer logging by setting `log4j.logger.kafka.authorizer.logger=INFO` in `log4j.properties`. Each ACL check generates a log line showing the principal, operation, resource, and allow/deny result. Export these logs to your SIEM and create alerts for: DENY events on sensitive topics (potential unauthorized access attempts), unexpected new consumer groups consuming from financial or PII topics, and produce operations from consumer-only principals (lateral movement indicator). For Confluent Platform, Audit Log enables structured JSON audit events with full principal and operation context.

Sources & references

  1. Apache Kafka Security Documentation
  2. Kafka SASL Configuration
  3. Kafka Authorization and ACLs

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.