适用场景
Apache Kafka 是主流分布式消息中间件,默认配置下 Kafka 安全机制完全关闭——任何能访问 9092 端口的客户端都可以自由读写任意 Topic。本教程适用于以下场景:将 Kafka 用于生产环境的业务团队,需要防止未授权客户端消费业务数据;多部门共用一个集群时,需要按 Topic 隔离读写权限;等保合规或客户审计要求记录接入方身份与访问行为。完成本教程后,你的 Kafka 集群将具备身份认证、传输加密与细粒度授权三层防护。
前置条件
- Kafka 2.7+ 集群(本文以 Kafka 3.6 为例,路径
/opt/kafka) - Zookeeper 或 KRaft 模式运行正常,集群节点时间同步
- Linux root 权限,节点间网络可达
- 已准备域名或 IP 用于生成证书(生产建议域名)
原理说明
Kafka 安全体系包含三个独立层面:认证(Authentication)确认客户端身份,本文采用 SASL/SCRAM-SHA-256 机制,用户名与加盐密码存储在 ZooKeeper 或 KRaft 元数据中;传输加密(Encryption)通过 SSL/TLS 保护客户端与 Broker 之间的数据流,防止中间人窃听;授权(Authorization)由 Kafka 自带的 ACL(Access Control Lists)实现,按”主体(Principal)—操作(Read/Write/Describe 等)—资源(Topic/Group)”三元组精确控制权限。三层叠加后,即使端口暴露,未授权客户端也无法完成任何操作。
操作步骤
第一步:配置 Broker 端 SASL
编辑 /opt/kafka/config/server.properties:
# 监听器与协议映射:9092 走 SASL+SSL
listeners=SASL_SSL://0.0.0.0:9092
advertised.listeners=SASL_SSL://kafka1.example.com:9092
sasl.enabled.mechanisms=SCRAM-SHA-256
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
security.inter.broker.protocol=SASL_SSL
# SSL 证书配置
ssl.keystore.location=/etc/kafka/ssl/server.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/etc/kafka/ssl/server.truststore.jks
ssl.truststore.password=changeit
ssl.client.auth=required
第二步:生成 SSL 证书与信任库
# 生成 Broker 密钥库(生产环境应使用 CA 签发,此处演示自签)
keytool -keystore /etc/kafka/ssl/server.keystore.jks -alias kafka -validity 3650 -genkeypair -keyalg RSA -storepass changeit -dname "CN=kafka1.example.com" -ext SAN=DNS:kafka1.example.com
# 导出并生成客户端信任库
keytool -keystore /etc/kafka/ssl/server.keystore.jks -exportcert -alias kafka -rfc -file /tmp/kafka.crt
keytool -keystore /etc/kafka/ssl/client.truststore.jks -alias kafka -import -file /tmp/kafka.crt -storepass changeit -noprompt
第三步:创建 SCRAM 用户
cd /opt/kafka
# 创建应用账号 app-user,权限组 admin 用于管理
bin/kafka-configs.sh --bootstrap-server localhost:9092 --alter --add-config 'SCRAM-SHA-256=[password=App@2026Secret],SCRAM-SHA-512=[password=App@2026Secret]' --entity-type users --entity-name app-user
# 创建 admin 账号(可执行集群管理操作)
bin/kafka-configs.sh --bootstrap-server localhost:9092 --alter --add-config 'SCRAM-SHA-256=[password=Admin@2026Secret]' --entity-type users --entity-name admin
第四步:配置 JAAS 文件
创建 /etc/kafka/kafka_server_jaas.conf:
KafkaServer {
org.apache.kafka.common.security.scram.ScramLoginModule required
username="admin"
password="Admin@2026Secret";
};
Client {
org.apache.kafka.common.security.scram.ScramLoginModule required
username="admin"
password="Admin@2026Secret";
};
在 bin/kafka-server-start.sh 的 KAFKA_OPTS 中引入 JAAS:
export KAFKA_OPTS="-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf"
第五步:配置并启用 ACL
在 server.properties 追加:
authorizer.class.name=kafka.security.authorizer.AclAuthorizer
super.users=User:admin
allow.everyone.if.no.acl.found=false
重启集群后,为 app-user 授权:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:app-user --operation Read,Write,Describe --topic orders --group app-group --command-config /etc/kafka/admin.properties
第六步:客户端连接配置
创建客户端配置文件 client.properties:
security.protocol=SASL_SSL
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="app-user" password="App@2026Secret";
ssl.truststore.location=/etc/kafka/ssl/client.truststore.jks
ssl.truststore.password=changeit
用控制台消费者验证:
bin/kafka-console-consumer.sh --bootstrap-server kafka1.example.com:9092 --topic orders --group app-group --consumer.config client.properties
配置验证
# 1. 未带认证信息连接,应被拒绝
bin/kafka-topics.sh --bootstrap-server localhost:9092 --list
# 报错: Unauthorized... 或认证失败
# 2. 带认证的 admin 用户可列出 Topic
bin/kafka-topics.sh --bootstrap-server localhost:9092 --list --command-config /etc/kafka/admin.properties
# 3. 验证 ACL 生效:app-user 尝试 Describe 未授权 Topic
bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic secret-topic --command-config client.properties
# 报错: Topic authorization failed
# 4. 用 openssl 验证 TLS 端口
openssl s_client -connect kafka1.example.com:9092 -tls1_2 < /dev/null | head -20
常见问题
FAQ 1:开启 ACL 后原有客户端全部连接失败?
这是预期行为——默认拒绝所有未授权操作。先保留 allow.everyone.if.no.acl.found=true 过渡,逐批为客户端配置账号并授权,验证通过后再改为 false 收紧。同时确认 super.users 已包含管理员,避免锁死集群。
FAQ 2:证书域名与连接地址不一致导致 TLS 握手失败?
SSL 握手失败最常见原因是证书 CN/SAN 与 advertised.listeners 中的主机名不匹配。确保证书包含客户端实际连接的域名,并使用 -ext SAN=DNS:<域名> 生成证书;多节点集群需要为每个 Broker 生成含各自 SAN 的证书。
总结
Kafka 安全加固分三步走:先用 SASL/SCRAM 建立身份认证,再用 SSL 加密传输链路,最后用 ACL 实现 Topic 级细粒度授权。生产环境中建议将密钥托管到 Vault 等密钥管理平台、启用 SCRAM 密码轮换,并将 ACL 变更纳入配置管理。三层面配置完成后,用未授权客户端反向验证拒绝效果,确保 Kafka 集群从”裸奔”状态升级为符合审计要求的可信数据通道。