Security: TLS, SASL, ACLs, and MSK IAM
Encryption in transit with TLS, authentication with SASL and mTLS, MSK IAM authentication, authorization with ACLs, and handling secrets in Spring.
The local lab runs with no security at all, which is fine on your machine and unacceptable in production. A production cluster must encrypt traffic, prove who each client is, and restrict what each client can do. This module covers the three layers, encryption, authentication, and authorization, with a focus on AWS MSK, and shows how to configure them from Spring.
What you’ll be able to do after this module
- Enable TLS encryption in transit between clients and brokers.
- Choose an authentication mechanism: SASL/SCRAM, mTLS, or MSK IAM.
- Restrict access with ACLs and least-privilege per service.
- Configure security from Spring without leaking secrets.
1. The three layers of Kafka security
Security is three distinct questions, each solved separately:
- Encryption: is the traffic private in transit? Solved by TLS.
- Authentication: who is this client? Solved by SASL, mTLS, or IAM.
- Authorization: what is this client allowed to do? Solved by ACLs.
flowchart TD
client["Spring client"]
tls["TLS: encrypt the connection"]
auth["Authenticate: SASL / mTLS / IAM"]
acl["Authorize: ACL check per operation"]
broker["Broker serves the request"]
client --> tls --> auth --> acl --> broker
A production cluster uses all three. Skipping any one leaves a gap: no TLS means traffic can be read, no auth means anyone can connect, no ACLs means any authenticated client can do anything.
2. Encryption in transit with TLS
TLS encrypts the connection between client and broker so credentials and payloads cannot be read on the wire. The client connects over the SSL or SASL_SSL security protocol and trusts the broker’s certificate.
spring:
kafka:
security:
protocol: SSL
ssl:
trust-store-location: file:/etc/kafka/client.truststore.jks
trust-store-password: ${KAFKA_TRUSTSTORE_PASSWORD}
On MSK, brokers present certificates signed by a public CA, so the JVM’s default trust store often already trusts them and you may not need a custom truststore. TLS alone encrypts but does not authenticate the client, which is the next layer.
3. Authentication
Authentication proves the client’s identity. There are three common mechanisms; pick based on your platform.
| Mechanism | How it works | Use when |
|---|---|---|
| SASL/SCRAM | Username and password, salted challenge | Self-managed or MSK with SCRAM |
| mTLS | Client presents its own certificate | Certificate-based environments |
| MSK IAM | AWS IAM credentials and policies | AWS MSK (the recommended default) |
On MSK, IAM authentication is the simplest to operate because it reuses AWS roles instead of separate Kafka credentials. The client authenticates with its IAM role, and there is no password to rotate.
spring:
kafka:
properties:
security.protocol: SASL_SSL
sasl.mechanism: AWS_MSK_IAM
sasl.jaas.config: software.amazon.msk.auth.iam.IAMLoginModule required;
sasl.client.callback.handler.class: software.amazon.msk.auth.iam.IAMClientCallbackHandler
For SASL/SCRAM instead, the client sends a username and password over the TLS-encrypted connection:
spring:
kafka:
properties:
security.protocol: SASL_SSL
sasl.mechanism: SCRAM-SHA-512
sasl.jaas.config: >
org.apache.kafka.common.security.scram.ScramLoginModule required
username="${KAFKA_USER}" password="${KAFKA_PASSWORD}";
4. Authorization with ACLs
Authentication says who you are; authorization says what you may do. Kafka access control lists (ACLs) grant a principal specific operations on specific resources, such as read a topic or join a group.
Grant the Payment service only what it needs: read orders, write payments, and use its consumer group.
# Payment service may read the orders topic
kafka-acls.sh --bootstrap-server $BROKER --add \
--allow-principal User:payment-service \
--operation Read --topic orders
# ...and write the payments topic
kafka-acls.sh --bootstrap-server $BROKER --add \
--allow-principal User:payment-service \
--operation Write --topic payments
# ...and use its consumer group
kafka-acls.sh --bootstrap-server $BROKER --add \
--allow-principal User:payment-service \
--operation Read --group payment-service
On MSK IAM, the same authorization is expressed as IAM policy statements attached to the service’s role rather than Kafka ACLs, which keeps access control in one place with the rest of your AWS permissions.
5. Least privilege per service
Give each service its own identity and only the permissions it uses. The goal is that a compromised or buggy service cannot touch topics it has no business touching.
- Order service: write
ordersonly. - Payment service: read
orders, writepayments, use grouppayment-service. - Notification service: read
orders,payments,inventory; writenotifications.
Avoid a single shared superuser credential across services. Distinct principals also make audit logs meaningful, because each action traces to one service.
6. Handling secrets in Spring
Security configuration references credentials, and those must never be hard-coded or committed. Externalize them.
- Inject secrets as environment variables or through a secrets manager (AWS Secrets Manager, Vault), referenced with
${...}placeholders as shown above. - Keep truststore and keystore passwords out of source control.
- With MSK IAM there is no static password at all, which removes an entire class of secret to manage.
7. Guided practical
The local lab runs plaintext, so this practical is exhibit-based and configuration-focused.
- Add a
SASL_SSLandSCRAM-SHA-512producer config to a service and read it against a SCRAM-enabled broker if you have one, or review the config against the MSK IAM variant. - Write the three
kafka-acls.shcommands that give the Payment service least privilege. - Identify which credential each config references and confirm all are
${...}placeholders, not literals. - For an MSK IAM setup, sketch the IAM policy statements equivalent to the ACLs above.
Next:Observability: Metrics, Consumer Lag, and Tracing, where you make a running system visible.