Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Security

Security configuration for Apache Kafka covering authentication, authorization, and encryption.


Kafka security encompasses three core areas:

Kafka SecurityAuthentication(Who are you?)Authorization(What can you do?)Encryption(Data protection)SASL/PLAINSASL/SCRAMSASL/GSSAPISASL/OAUTHBEARERmTLSACLsTLS in-transitAt-rest encryption
Security LayerPurposeMechanisms
AuthenticationVerify client identitySASL (PLAIN, SCRAM, GSSAPI, OAUTHBEARER), mTLS
AuthorizationControl access to resourcesACLs (Access Control Lists)
EncryptionProtect data confidentialityTLS (in-transit), filesystem encryption (at-rest)

MechanismDescriptionUse Case
SASL/PLAINUsername/password (plaintext)Development, simple setups
SASL/SCRAMSalted Challenge ResponseProduction without Kerberos
SASL/GSSAPIKerberos authenticationEnterprise environments
SASL/OAUTHBEAREROAuth 2.0 tokensCloud-native, OAuth infrastructure
mTLSMutual TLS certificatesCertificate-based auth

SCRAM (Salted Challenge Response Authentication Mechanism) provides secure password-based authentication.

Broker configuration:

server.properties
listeners=SASL_SSL://0.0.0.0:9093
advertised.listeners=SASL_SSL://kafka1:9093
security.inter.broker.protocol=SASL_SSL
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-512
sasl.enabled.mechanisms=SCRAM-SHA-512
# TLS configuration
ssl.keystore.location=/etc/kafka/ssl/kafka.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/etc/kafka/ssl/kafka.truststore.jks
ssl.truststore.password=truststore-password

Create SCRAM credentials:

Terminal window
# Create user
kafka-configs.sh --bootstrap-server kafka:9092 \
--alter \
--add-config 'SCRAM-SHA-512=[password=user-password]' \
--entity-type users \
--entity-name alice
# For inter-broker communication
kafka-configs.sh --bootstrap-server kafka:9092 \
--alter \
--add-config 'SCRAM-SHA-512=[password=broker-password]' \
--entity-type users \
--entity-name kafka-broker

Client configuration:

security.protocol=SASL_SSL
sasl.mechanism=SCRAM-SHA-512
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
username="alice" \
password="user-password";
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password

Mutual TLS authenticates both client and server using certificates.

Broker configuration:

listeners=SSL://0.0.0.0:9093
advertised.listeners=SSL://kafka1:9093
security.inter.broker.protocol=SSL
ssl.keystore.location=/etc/kafka/ssl/kafka.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/etc/kafka/ssl/kafka.truststore.jks
ssl.truststore.password=truststore-password
# Require client certificates
ssl.client.auth=required

Client configuration:

security.protocol=SSL
ssl.keystore.location=/etc/kafka/ssl/client.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password

OAuth 2.0 authentication for token-based systems.

Broker configuration:

listeners=SASL_SSL://0.0.0.0:9093
sasl.enabled.mechanisms=OAUTHBEARER
# Custom callback handler for token validation
listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class=\
org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallbackHandler
# JWKS endpoint for token validation
listener.name.sasl_ssl.oauthbearer.sasl.jaas.config=\
org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \
unsecuredLoginStringClaim_sub="admin";

Authentication Guide


Kafka ACLs define who can perform what operations on which resources.

ACL StructurePrincipal(Who)Permission(Allow/Deny)Operation(What)Resource(Where)Host(From where)User:aliceUser:CN=client.example.comGroup:developersRead, Write, CreateDelete, Alter, DescribeClusterAction, AllTopic, Group, ClusterTransactionalIdDelegationToken
ComponentDescriptionExamples
PrincipalUser or group identityUser:alice, User:CN=client.example.com
PermissionAllow or DenyALLOW, DENY
OperationAction to performRead, Write, Create, Delete, Describe, Alter
ResourceKafka resourceTopic:orders, Group:order-processor, Cluster:kafka-cluster
HostSource IP*, 192.168.1.100
Terminal window
# Grant producer access to topic
kafka-acls.sh --bootstrap-server kafka:9092 \
--add \
--allow-principal User:producer-app \
--operation Write \
--operation Describe \
--topic orders
# Grant consumer access to topic and group
kafka-acls.sh --bootstrap-server kafka:9092 \
--add \
--allow-principal User:consumer-app \
--operation Read \
--operation Describe \
--topic orders \
--group order-processor
# Grant admin access to all topics
kafka-acls.sh --bootstrap-server kafka:9092 \
--add \
--allow-principal User:admin \
--operation All \
--topic '*'
# List ACLs
kafka-acls.sh --bootstrap-server kafka:9092 --list
# List ACLs for specific topic
kafka-acls.sh --bootstrap-server kafka:9092 \
--list \
--topic orders
# Remove ACL
kafka-acls.sh --bootstrap-server kafka:9092 \
--remove \
--allow-principal User:producer-app \
--operation Write \
--topic orders
Use CaseACLs Required
ProducerWrite, Describe on topic; Create if auto-create enabled
ConsumerRead, Describe on topic; Read on consumer group
Transactional producerWrite on topic; Write on transactional ID; Describe on cluster
Kafka ConnectRead/Write on topics; Read/Write on internal topics; Describe on cluster
AdminAll on cluster; All on topics
server.properties
# Enable ACL authorizer
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
# Super users (bypass ACLs)
super.users=User:admin;User:kafka-broker
# Default when no ACL matches (deny recommended for production)
allow.everyone.if.no.acl.found=false

Authorization Guide


TLS encrypts data in transit between clients and brokers, and between brokers.

ProducerBroker 1Broker 2ConsumerTLS encrypts all network trafficDisables zero-copy optimizationTLSTLS (inter-broker)TLS
Terminal window
# Generate CA
openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 \
-subj "/CN=Kafka-CA"
# Generate broker keystore
keytool -keystore kafka.keystore.jks -alias kafka-broker \
-validity 365 -genkey -keyalg RSA \
-dname "CN=kafka1.example.com"
# Create CSR
keytool -keystore kafka.keystore.jks -alias kafka-broker \
-certreq -file kafka-broker.csr
# Sign certificate
openssl x509 -req -CA ca-cert -CAkey ca-key \
-in kafka-broker.csr -out kafka-broker-signed.crt \
-days 365 -CAcreateserial
# Import CA and signed cert
keytool -keystore kafka.keystore.jks -alias CARoot \
-import -file ca-cert
keytool -keystore kafka.keystore.jks -alias kafka-broker \
-import -file kafka-broker-signed.crt
# Create truststore
keytool -keystore kafka.truststore.jks -alias CARoot \
-import -file ca-cert
listeners=SSL://0.0.0.0:9093
advertised.listeners=SSL://kafka1.example.com:9093
security.inter.broker.protocol=SSL
ssl.keystore.location=/etc/kafka/ssl/kafka.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/etc/kafka/ssl/kafka.truststore.jks
ssl.truststore.password=truststore-password
# TLS protocol versions
ssl.enabled.protocols=TLSv1.3,TLSv1.2
ssl.protocol=TLSv1.3
# Cipher suites (optional - use defaults for TLS 1.3)
ssl.cipher.suites=TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256

TLS Disables Zero-Copy

TLS encryption requires data to pass through user space for encryption/decryption, disabling Kafka's zero-copy optimization. This can reduce throughput by 30-50% depending on workload and hardware.

AspectWithout TLSWith TLS
Zero-copyEnabledDisabled
CPU usageLowerHigher (encryption overhead)
ThroughputHigher30-50% reduction typical
LatencyLowerSlightly higher

Encryption Guide


PracticeRationale
Use SCRAM-SHA-512 or strongerAvoid plaintext passwords
Rotate credentials regularlyLimit exposure window
Use separate credentials per applicationLimit blast radius
Use mTLS for service-to-serviceCertificate-based identity
PracticeRationale
Deny by defaultExplicit allow only
Principle of least privilegeMinimum required access
Use groups/roles where possibleEasier management
Audit ACL changesTrack access modifications
Separate admin credentialsProtect administrative access
PracticeRationale
Enable TLS for all listenersEncrypt all traffic
Use TLS 1.3 where possibleStrongest protocol
Rotate certificates before expiryMaintain continuity
Use strong cipher suitesAvoid weak encryption
Consider at-rest encryptionProtect stored data
PracticeRationale
Enable audit loggingTrack security events
Monitor authentication failuresDetect attacks
Regular security reviewsIdentify misconfigurations
Patch regularlyAddress vulnerabilities
Network segmentationLimit network exposure

# Different security per listener
listeners=PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9093,SASL_SSL://0.0.0.0:9094
advertised.listeners=PLAINTEXT://kafka1:9092,SSL://kafka1:9093,SASL_SSL://kafka1:9094
# Inter-broker uses SASL_SSL
security.inter.broker.protocol=SASL_SSL
# Listener-specific configuration
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_SSL:SASL_SSL
listener.name.sasl_ssl.scram-sha-512.sasl.jaas.config=\
org.apache.kafka.common.security.scram.ScramLoginModule required \
username="kafka-broker" \
password="broker-password";
# Internal (within datacenter) - SASL_PLAINTEXT
# External (from internet) - SASL_SSL
listeners=INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9093
advertised.listeners=INTERNAL://kafka1.internal:9092,EXTERNAL://kafka1.example.com:9093
listener.security.protocol.map=INTERNAL:SASL_PLAINTEXT,EXTERNAL:SASL_SSL
inter.broker.listener.name=INTERNAL

Security can be incrementally enabled on an existing cluster without downtime through a phased rolling restart approach.

Phase 1: Open Secured PortsPhase 2: Migrate ClientsPhase 3: Secure Inter-BrokerPhase 4: Close PLAINTEXTlisteners=PLAINTEXT::9091,SSL::9092PLAINTEXT remains opensecurity.inter.broker.protocol=SSLBrokers communicate securelylisteners=SSL://:9092PLAINTEXT removedRolling restartClient migrationRolling restart

Add secured listener while keeping PLAINTEXT open:

# server.properties - Phase 1
listeners=PLAINTEXT://0.0.0.0:9091,SSL://0.0.0.0:9092

Perform rolling restart of all brokers.

Update client configurations to use the secured port:

client.properties
bootstrap.servers=kafka1:9092,kafka2:9092,kafka3:9092
security.protocol=SSL
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=truststore-password

Restart clients to pick up new configuration.

Configure brokers to use SSL for inter-broker communication:

# server.properties - Phase 3
listeners=PLAINTEXT://0.0.0.0:9091,SSL://0.0.0.0:9092
security.inter.broker.protocol=SSL

Perform rolling restart of all brokers.

Remove the insecure listener:

# server.properties - Phase 4
listeners=SSL://0.0.0.0:9092
security.inter.broker.protocol=SSL

Perform final rolling restart.

To add SASL authentication on top of SSL encryption, open an additional SASL_SSL port:

Phase 1:

listeners=PLAINTEXT://0.0.0.0:9091,SSL://0.0.0.0:9092,SASL_SSL://0.0.0.0:9093

Phase 2: Migrate clients to SASL_SSL port (9093)

Phase 3:

listeners=PLAINTEXT://0.0.0.0:9091,SSL://0.0.0.0:9092,SASL_SSL://0.0.0.0:9093
security.inter.broker.protocol=SSL

Phase 4:

listeners=SSL://0.0.0.0:9092,SASL_SSL://0.0.0.0:9093
security.inter.broker.protocol=SSL

Rolling Restart Best Practices

  • Stop brokers gracefully using SIGTERM
  • Wait for restarted broker to rejoin ISR before proceeding to next broker
  • Monitor under-replicated partitions during the process
  • Keep PLAINTEXT listener open until all clients have migrated