这是《Kafka 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 默认的 PLAINTEXT 监听等于“裸奔”:任何能连通端口的人都能读写所有 topic。本章讲清楚三层安全模型,并给出可落地的配置。
21.1 安全的三个层次
加密(Encryption) 数据在网络上不可被窃听 SSL/TLS
认证(Authentication) 你是谁 SASL / mTLS
授权(Authorization) 你能做什么 ACL
三者独立且都要做:只加密不认证,等于只防窃听不防冒充;只认证不加密,凭据和数据仍可能被嗅探。
21.2 监听器与协议
Broker 通过监听器组合不同协议:
listeners=SSL://:9093,SASL_SSL://:9094
advertised.listeners=SSL://broker1:9093,SASL_SSL://broker1:9094
listener.security.protocol.map=SSL:SSL,SASL_SSL:SASL_SSL
| 协议 | 含义 |
|---|---|
| PLAINTEXT | 无加密无认证(仅内网可信环境) |
| SSL | TLS 加密,可选 mTLS 双向认证 |
| SASL_PLAINTEXT | 认证但不加密 |
| SASL_SSL | 认证 + 加密(推荐) |
实践建议:内部服务用 SASL_SSL 或 SSL;管理端口可用单独监听器加 ACL 收敛权限。
21.3 SASL/SCRAM:最常用的认证
SCRAM 的用户与凭据存在 ZooKeeper/KRaft 元数据中(而非静态 JAAS 文件),支持动态增删,运维友好。以 SCRAM-SHA-256 为例。
1. 创建用户(在任意 Broker 机器执行)
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --add-config 'SCRAM-SHA-256=[iterations=8192,password=app-secret]' \
--entity-type users --entity-name app-producer
查看:
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--describe --entity-type users --entity-name app-producer
2. Broker 端配置
listeners=SASL_SSL://:9094
advertised.listeners=SASL_SSL://broker1:9094
listener.security.protocol.map=SASL_SSL:SASL_SSL
sasl.enabled.mechanisms=SCRAM-SHA-256
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
# Broker 之间互联也需要账号(这里用 admin)
listener.name.sasl_ssl.scram-sha-256.sasl.jaas.config=\
org.apache.kafka.common.security.scram.ScramLoginModule required \
username="admin" \
password="admin-secret";
3. 客户端配置
security.protocol=SASL_SSL
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
username="app-producer" \
password="app-secret";
SCRAM-SHA-512 更强,PLAIN 只建议配合 SSL 在测试环境使用。
21.4 SSL/TLS:加密与双向认证
证书准备(生产用公司 CA,测试可用自签)
# 1. 生成 CA
openssl req -new -x509 -keyout ca-key -out ca-cert -days 3650 \
-subj "/CN=TestCA"
# 2. 每台 Broker 生成密钥与 CSR,并用 CA 签发
keytool -keystore broker1.keystore.p12 -storetype PKCS12 \
-alias broker1 -genkey -keyalg RSA -validity 3650 \
-dname "CN=broker1.example.com"
keytool -keystore broker1.keystore.p12 -alias broker1 \
-certreq -file broker1.csr
openssl x509 -req -CA ca-cert -CAkey ca-key \
-in broker1.csr -out broker1-signed.pem -days 3650 -CAcreateserial
# 3. 导入 CA 与签发证书到 keystore,导入 CA 到 truststore
keytool -keystore broker1.keystore.p12 -alias CARoot \
-import -file ca-cert
keytool -keystore broker1.keystore.p12 -alias broker1 \
-import -file broker1-signed.pem
keytool -keystore truststore.p12 -alias CARoot \
-importcert -file ca-cert -noprompt
Broker 配置
listeners=SSL://:9093
ssl.keystore.location=/etc/kafka/ssl/broker1.keystore.p12
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/etc/kafka/ssl/truststore.p12
ssl.truststore.password=changeit
ssl.client.auth=required # mTLS 双向认证;none 表示仅加密
客户端配置
security.protocol=SSL
ssl.truststore.location=/path/truststore.p12
ssl.truststore.password=changeit
# mTLS 时客户端也需要证书
ssl.keystore.location=/path/client.keystore.p12
ssl.keystore.password=changeit
TLS 会增加 CPU 与延迟,大流量集群建议评估硬件加速,并保持长连接复用。
21.5 ACL 授权
认证解决“你是谁”,ACL 决定“你能干什么”。前提:
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer # KRaft
# ZK 模式: kafka.security.authorizer.AclAuthorizer
allow.everyone.if.no.acl.found=false # 默认拒绝
super.users=User:admin;User:broker1 # 管理与 Broker 互联账号
常用 ACL 操作
BOOTSTRAP=localhost:9094
CMD=(bin/kafka-acls.sh --bootstrap-server $BOOTSTRAP \
--command-config admin.properties) # admin.properties 含管理员认证
# 生产者:写 order-events
"${CMD[@]}" --add --allow-principal User:app-producer \
--producer --topic order-events
# 消费者:读 order-events + 读消费组
"${CMD[@]}" --add --allow-principal User:order-consumer \
--consumer --topic order-events --group order-service
# 只读某前缀的所有 topic
"${CMD[@]}" --add --allow-principal User:report \
--operation READ --resource-pattern-type prefixed --topic report-
# 列出 ACL
"${CMD[@]}" --list
# 删除
"${CMD[@]}" --remove --allow-principal User:app-producer \
--producer --topic order-events
最小权限示例矩阵:
| 主体 | topic 权限 | 组权限 | 集群权限 |
|---|---|---|---|
| producer-app | WRITE 特定 topic | 无 | 无 |
| consumer-app | READ 特定 topic | READ 特定组 | 无 |
| connect-worker | 读写内部 topic | 组权限 | Describe |
| admin | 全部 | 全部 | 全部 |
21.6 Spring Boot 客户端配置
spring:
kafka:
bootstrap-servers: broker1:9094
security:
protocol: SASL_SSL
properties:
sasl.mechanism: SCRAM-SHA-256
sasl.jaas.config: >
org.apache.kafka.common.security.scram.ScramLoginModule required
username="app-producer"
password="app-secret";
ssl.truststore.location: /etc/app/truststore.p12
ssl.truststore.password: changeit
凭据不要进 Git:用环境变量、Vault、K8s Secret 注入。
21.7 安全最佳实践清单
网络:
[ ] Kafka 只在内网/私网监听,必要时才经网关暴露
[ ] Broker 间与 Controller 通道启用 TLS/SASL
认证:
[ ] 禁用 PLAINTEXT 或仅限运维白名单
[ ] 不同应用使用不同主体(不要一个账号走天下)
[ ] 凭据集中管理,定期轮换
授权:
[ ] allow.everyone.if.no.acl.found=false
[ ] 最小权限:读写分离、按 topic/组授权
[ ] ACL 变更走审批与审计
审计与加密:
[ ] 开启审计日志(谁读写了什么)
[ ] 敏感数据在业务层额外加密(Kafka 不理解内容)
本章小结
- 安全是加密、认证、授权三层叠加,缺一不可;
- SASL/SCRAM 支持动态用户管理,是最常用的认证方案;
- SSL 提供传输加密,mTLS 还能同时完成客户端认证;
- ACL 以“主体 + 操作 + 资源”建模,默认拒绝 + 最小权限;
- 凭据用 Secret/Vault 管理,永远不要提交进仓库。
思考题
- 只启用 ACL 不启用认证,安全模型还成立吗?为什么?
- Broker 之间也需要账号吗?如果配置错误会出现什么现象?
- 设计多租户 Kafka 的权限模型:租户 A 的服务如何绝对无法读租户 B 的 topic?