Kafka Security (SSL/TLS)
Everything so far ran on a plaintext local cluster. This module is the one thing standing between this reference architecture and something you'd actually be allowed to run against a real production broker.
Learning objectives
- Beginner: Explain why a plaintext local Kafka cluster is unsafe to run against a real production broker unmodified.
- Intermediate: Set up SSL/TLS on a local Kafka cluster and configure both a producer and consumer to use it.
- Advanced: Reason about how enterprises manage SSL certificate rotation for a Kafka cluster without downtime.
◆ The problem
Every setup in this site so far used a plaintext (PLAINTEXT://) listener — anyone who can reach the broker's port can read every record on every topic, and any client can connect and produce/consume without proving who it is. On a shared network, or anything beyond an isolated local dev box, that's an open door to both eavesdropping and impersonation.
Kafka's threat model at the transport layer has two concerns: confidentiality (can someone on the network read the bytes?) and authentication (is the client actually who it claims to be?). SSL/TLS addresses both — encrypting the connection and (optionally, via mutual TLS) requiring the client to present its own certificate.
SSL/TLS secures a connection through a handshake: the server presents a certificate (its identity, signed by a trusted Certificate Authority); the client verifies that signature against CAs it trusts; the two sides then negotiate a shared symmetric encryption key for the rest of the session (asymmetric crypto is used only to bootstrap trust — it's too slow to encrypt a whole session with).
Simplified TLS handshake. Certificate verification against a trusted CA is what prevents a client from being fooled into trusting an impostor broker.
Rather than every broker presenting a self-signed certificate (which every client would then need to individually trust, and which offers no real identity guarantee), enterprises operate or use a Certificate Authority: an entity whose own root certificate is pre-trusted by everything in the organization, which signs certificates on behalf of individual brokers/services after verifying their identity. Any certificate the CA signs is automatically trusted by anything that trusts the CA — this is what lets a fleet of brokers all present valid, verifiable certificates without every client needing a bespoke trust list per broker.
# 1. Generate a CA key + self-signed CA certificate openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 # 2. Create the broker's own keystore + key pair keytool -keystore kafka.server.keystore.jks -alias localhost -validity 365 -genkey # 3. Create a certificate signing request (CSR) from the broker's keystore keytool -keystore kafka.server.keystore.jks -alias localhost -certreq -file cert-file # 4. Sign the broker's certificate with the CA openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days 365 -CAcreateserial # 5. Import the CA cert, then the signed broker cert, into the broker's keystore keytool -keystore kafka.server.keystore.jks -alias CARoot -import -file ca-cert keytool -keystore kafka.server.keystore.jks -alias localhost -import -file cert-signed # 6. Build a truststore containing just the CA cert — anything signed by this CA is trusted keytool -keystore kafka.server.truststore.jks -alias CARoot -import -file ca-cert
listeners=SSL://:9093 ssl.keystore.location=/certs/kafka.server.keystore.jks ssl.keystore.password=changeit ssl.truststore.location=/certs/kafka.server.truststore.jks ssl.truststore.password=changeit
▲ Pitfall
The self-signed CA workflow above is for local learning only. In a real enterprise setup, brokers request signing from an actual internal or public CA rather than a throwaway self-signed one, and keystore/truststore passwords and private keys are managed as Secrets (Module 20 §9) or through a dedicated secrets manager — never committed to source control.
💻 Code example
# 1. Generate a CA key + self-signed CA certificate openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 # 2. Create the broker's own keystore + key pair keytool -keystore kafka.server.keystore.jks -alias localhost -validity 365 -genkey # 3. Create a certificate signing request (CSR) from the broker's keystore keytool -keystore kafka.server.keystore.jks -alias localhost -certreq -file cert-file # 4. Sign the broker's certificate with the CA openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days 365 -CAcreateserial # 5. Import the CA cert, then the signed broker cert, into the broker's keystore keytool -keystore kafka.server.keystore.jks -alias CARoot -import -file ca-cert keytool -keystore kafka.server.keystore.jks -alias localhost -import -file cert-signed # 6. Build a truststore containing just the CA cert — anything signed by this CA is trusted keytool -keystore kafka.server.truststore.jks -alias CARoot -import -file ca-cert
spring: kafka: producer: bootstrap-servers: localhost:9093 properties: security.protocol: SSL ssl.truststore.location: /certs/kafka.client.truststore.jks ssl.truststore.password: changeit ssl.keystore.location: /certs/kafka.client.keystore.jks ssl.keystore.password: changeit ssl.key.password: changeit ssl.endpoint.identification.algorithm: ""
A client only strictly NEEDS a truststore (to verify the broker's certificate) for one-way TLS. This setup uses two-way (mutual) TLS — the broker also verifies the CLIENT's identity — so the client needs its own keystore too, mirroring the handshake from §21.2 with roles reversed: ssl.keystore.location/ssl.keystore.password hold the client's own signed certificate, and ssl.key.password protects the private key inside it. ssl.endpoint.identification.algorithm set to an empty string disables hostname verification against the certificate's CN/SAN — fine for this local localhost setup with a self-signed CA, but something you'd normally leave at its default (https) in production, where the cert's hostname should genuinely match the broker you're connecting to.
💻 Code example
spring: kafka: producer: bootstrap-servers: localhost:9093 properties: security.protocol: SSL ssl.truststore.location: /certs/kafka.client.truststore.jks ssl.truststore.password: changeit ssl.keystore.location: /certs/kafka.client.keystore.jks ssl.keystore.password: changeit ssl.key.password: changeit ssl.endpoint.identification.algorithm: ""
spring: kafka: consumer: bootstrap-servers: localhost:9093 properties: security.protocol: SSL ssl.truststore.location: /certs/kafka.client.truststore.jks ssl.truststore.password: changeit ssl.keystore.location: /certs/kafka.client.keystore.jks ssl.keystore.password: changeit ssl.key.password: changeit ssl.endpoint.identification.algorithm: ""
Same keystore + truststore pair as the producer (§21.3) — both sides of this app need to present their own certificate to the broker, because this setup uses two-way (mutual) TLS, not just one-way.
◆ Under the hood — how this composes with Module 20
In a real Kubernetes deployment, the keystore/truststore files above aren't baked into the container image — they're mounted from a volume-backed Secret (Module 20 §9's second row), exactly because SSL material is multi-file, sensitive, and something the app reads from disk rather than an env var.
✓ Quick recap
What two concerns does SSL/TLS address for a Kafka client-broker connection? Confidentiality (encryption) and authentication (verifying identity via a trusted CA-signed certificate). Why does a CA-based model scale better than every broker using a self-signed certificate? Clients only need to trust the CA once; every certificate the CA signs is then automatically trusted, without a bespoke per-broker trust list. Does a Kafka client need its own keystore, not just a truststore? Only for mutual TLS, where the broker also verifies the client's identity — a truststore alone is enough to just verify the broker. (This chapter's own setup IS mutual TLS, which is why both the producer and consumer configs above include a keystore, not just a truststore.)
💻 Code example
spring: kafka: consumer: bootstrap-servers: localhost:9093 properties: security.protocol: SSL ssl.truststore.location: /certs/kafka.client.truststore.jks ssl.truststore.password: changeit ssl.keystore.location: /certs/kafka.client.keystore.jks ssl.keystore.password: changeit ssl.key.password: changeit ssl.endpoint.identification.algorithm: ""
Want a visual for this concept?
Generate a diagram tailored to “Kafka Security (SSL/TLS)” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →