Kafka 授权与 ACL 深入实践
一、授权框架概览:开启可插拔 Authorizer
Kafka 内置可插拔的授权框架,通过 authorizer.class.name
指定 Authorizer 实现。被配置实现需继承 org.apache.kafka.server.authorizer.Authorizer
。
KRaft 模式下,Kafka 提供默认实现,将 ACL 存储在 集群元数据(KRaft 元数据日志) 中。请在 所有节点(broker、controller 或二者合一)设置:
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
🔎 延伸阅读:ACL 结构详见 KIP-11,资源模式详见 KIP-290。日常增删查 ACL 使用
kafka-acls.sh
。
二、资源无 ACL 的默认行为与“允许所有人”的开关
1)默认:不匹配 ACL = 拒绝访问
当资源(R)未定义任何 ACL(即没有 ACL 命中该资源)时,Kafka 默认限制访问,只有 super users 可访问。
2)切换为“无 ACL 即允许所有人”
如需改成 没有 ACL 时对所有用户可访问,在 server.properties
中加入:
allow.everyone.if.no.acl.found=true
说明:一旦资源存在一条或多条 ACL,则仍以 ACL 的匹配规则为准,与上述开关无关。
3)配置超级用户
分隔符为分号(SSL 用户名可能包含逗号);默认 PrincipalType
字符串 "User"
区分大小写:
super.users=User:Bob;User:Alice
三、KRaft 中的 Principal 转发(Envelope)
在 KRaft 集群里,客户端的管理类请求(如 CreateTopics
/DeleteTopics
)先发往 broker 的监听器,broker 再通过 controller.listener.names
中第一个监听器将请求转发给 active controller。
授权在 controller 上完成,机制为 Envelope:将底层请求与客户端 principal一并封装转发。
- controller 首先用 已认证的 broker principal 授权 Envelope 请求;
- 然后用 被转发的客户端 principal 授权底层请求。
因此,Kafka 必须会序列化/反序列化客户端 principal。若自定义 principal,需要:
- 通过
principal.builder.class
覆盖构建器;- 该类实现
org.apache.kafka.common.security.auth.KafkaPrincipalSerde
(用于序列化/反序列化 principal)。默认构建器:
org.apache.kafka.common.security.authenticator.DefaultKafkaPrincipalBuilder
使用 RPC 定义:clients/src/main/resources/common/message/DefaultPrincipalData.json
四、映射用户名:SSL 与 SASL(Kerberos)
1)SSL 用户名映射:ssl.principal.mapping.rules
默认 SSL 用户名形如:
"CN=writeuser,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown"
可用 ssl.principal.mapping.rules
将 X.500 DN 映射为短名。按序匹配,首次命中即用,后续忽略;支持 /L
(小写)、/U
(大写):
RULE:pattern/replacement/
RULE:pattern/replacement/[LU]
示例(含大小写规范及通配):
ssl.principal.mapping.rules=\RULE:^CN=(.*?),OU=ServiceUsers.*$/$1/,\RULE:^CN=(.*?),OU=(.*?),O=(.*?),L=(.*?),ST=(.*?),C=(.*?)$/$1@$2/L,\RULE:^.*[Cc][Nn]=([a-zA-Z0-9.]*).*$/$1/L,\DEFAULT
"CN=serviceuser,OU=ServiceUsers,...” → "serviceuser"
"CN=adminUser,OU=Admin,...” → "adminuser@admin"
自定义 PrincipalBuilder:
principal.builder.class=CustomizedPrincipalBuilderClass
2)SASL(Kerberos)用户名映射:sasl.kerberos.principal.to.local.rules
默认 SASL 用户名为 Kerberos principal 的 primary 部分。可在 server.properties
中用与 krb5.conf
中 auth_to_local
同构的规则改写(同样支持 /L
、/U
):
RULE:[n:string](regexp)s/pattern/replacement/
RULE:[n:string](regexp)s/pattern/replacement/g
RULE:[n:string](regexp)s/pattern/replacement//L
RULE:[n:string](regexp)s/pattern/replacement/g/L
RULE:[n:string](regexp)s/pattern/replacement//U
RULE:[n:string](regexp)s/pattern/replacement/g/U
示例:将 user@MYDOMAIN.COM
→ user
,同时保留默认规则:
sasl.kerberos.principal.to.local.rules=\RULE:[1:$1@$0](.*@MYDOMAIN.COM)s/@.*//,DEFAULT
五、kafka-acls.sh
:CLI 全参与高频用法
CLI 位于 bin/
目录,脚本名 kafka-acls.sh
。参数全集(与官方一致):
-
动作类:
--add
、--remove
、--list
-
连接配置:
--bootstrap-server
(连 broker)、--bootstrap-controller
(连 controller)二选一
--command-config
(Admin Client 用属性文件,仅配合--bootstrap-server
) -
资源模式:
--cluster
、--topic [topic-name]
、--group [group-name]
、
--transactional-id [transactional-id]
(*
=全部)、
--delegation-token [delegation-token]
(*
=全部)、
--user-principal [user-principal]
(现用于 delegation tokens;*
=全部)、
--resource-pattern-type [pattern-type]
:添加时literal|prefixed
;列出/移除时可any|match
⚠️
--remove
+match
慎用(会批量移除所有匹配模式的 ACL) -
主体与来源:
--allow-principal
、--deny-principal
、--principal
(列出时过滤)
--allow-host
、--deny-host
(仅 IP,不支持主机名;未显式指定时默认*
) -
操作名:
Read|Write|Create|Delete|Alter|Describe|ClusterAction|DescribeConfigs|AlterConfigs|IdempotentWrite|CreateTokens|DescribeTokens|All
-
便捷选项:
--producer
(生成 WRITE/DESCRIBE/CREATE@topic)
--consumer
(生成 READ/DESCRIBE@topic + READ@group)
--idempotent
(与--producer
同用;或由 transactional-id 授权自动启用)
--force
(无交互确认)
典型操作示例
1)添加:允许 User:Bob
与 User:Alice
从指定 IP 对 Test-topic
执行 Read/Write
:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:Bob \--allow-principal User:Alice \--allow-host 198.51.100.0 \--allow-host 198.51.100.1 \--operation Read --operation Write \--topic Test-topic
2)“允许所有 + 拒绝个别”:允许所有用户从任意主机读 Test-topic
,但拒绝 User:BadBob
自 198.51.100.3
读取:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:'*' --allow-host '*' \--deny-principal User:BadBob --deny-host 198.51.100.3 \--operation Read --topic Test-topic
3)对所有 Topic(通配 *
)授 Producer 权限:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:Peter \--allow-host 198.51.200.1 \--producer --topic '*'
4)前缀模式:允许 User:Jane
向以 Test-
开头的主题生产:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:Jane \--producer --topic Test- \--resource-pattern-type prefixed
5)移除 ACL(与添加相同参数,改 --remove
即可):
bin/kafka-acls.sh --bootstrap-server localhost:9092 --remove \--allow-principal User:Bob --allow-principal User:Alice \--allow-host 198.51.100.0 --allow-host 198.51.100.1 \--operation Read --operation Write \--topic Test-topic
6)列出 ACL:
-
精确资源(literal):
bin/kafka-acls.sh --bootstrap-server localhost:9092 --list --topic Test-topic
-
通配
*
:bin/kafka-acls.sh --bootstrap-server localhost:9092 --list --topic '*'
-
列出影响
Test-topic
的全部(含 literal、wildcard、prefixed):bin/kafka-acls.sh --bootstrap-server localhost:9092 --list \--topic Test-topic --resource-pattern-type match
7)按“角色”快速授权:
-
设
User:Bob
为Test-topic
生产者:bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:Bob --producer --topic Test-topic
-
设
User:Bob
为Test-topic
消费者,消费组Group-1
(必须指定--group
):bin/kafka-acls.sh --bootstrap-server localhost:9092 --add \--allow-principal User:Bob --consumer --topic Test-topic --group Group-1
六、授权原语:操作(Operations)与资源(Resources)
1)操作集合
Read | Write | Create | Delete | Alter | Describe | ClusterAction | DescribeConfigs | AlterConfigs | IdempotentWrite | CreateTokens | DescribeTokens | All
2)资源集合与错误码
- Topic:主题。失败 →
TOPIC_AUTHORIZATION_FAILED (29)
- Group:消费组。失败 →
GROUP_AUTHORIZATION_FAILED (30)
- Cluster:集群。失败 →
CLUSTER_AUTHORIZATION_FAILED (31)
- TransactionalId:事务标识。失败 →
TRANSACTIONAL_ID_AUTHORIZATION_FAILED (53)
- DelegationToken:委派令牌(详见 KIP-48)
- User:用户(
CreateToken
/DescribeToken
可授予到 User,详见 KIP-373)
七、权责矩阵:Kafka 协议 × 操作 × 资源(完整版)
下表直接复刻官方映射(按原文顺序),用于设计“最小权限”与审计。
注:若同一 API 同时列出多条,表示该请求可能触达多种授权路径或需要叠加校验。
Protocol (API key) | Operation | Resource | Note |
---|---|---|---|
PRODUCE (0) | Write | TransactionalId | 事务生产者设置了 transactional.id 时需要。 |
PRODUCE (0) | IdempotentWrite | Cluster | 幂等写。 |
PRODUCE (0) | Write | Topic | 普通生产。 |
FETCH (1) | ClusterAction | Cluster | follower 拉取分区数据。 |
FETCH (1) | Read | Topic | 普通消费者读取分区。 |
LIST_OFFSETS (2) | Describe | Topic | — |
METADATA (3) | Describe | Topic | — |
METADATA (3) | Create | Cluster | 自动建主题先查集群级;无则查 Topic 级。 |
METADATA (3) | Create | Topic | 自动建主题(当集群级无权限)。 |
LEADER_AND_ISR (4) | ClusterAction | Cluster | — |
STOP_REPLICA (5) | ClusterAction | Cluster | — |
UPDATE_METADATA (6) | ClusterAction | Cluster | — |
CONTROLLED_SHUTDOWN (7) | ClusterAction | Cluster | — |
OFFSET_COMMIT (8) | Read | Group | 先组后题。 |
OFFSET_COMMIT (8) | Read | Topic | — |
OFFSET_FETCH (9) | Describe | Group | 先组后题。 |
OFFSET_FETCH (9) | Describe | Topic | — |
FIND_COORDINATOR (10) | Describe | Group | 请求类型为 Group 时。 |
FIND_COORDINATOR (10) | Describe | TransactionalId | 事务生产者找事务协调者。 |
JOIN_GROUP (11) | Read | Group | — |
HEARTBEAT (12) | Read | Group | — |
LEAVE_GROUP (13) | Read | Group | — |
SYNC_GROUP (14) | Read | Group | — |
DESCRIBE_GROUPS (15) | Describe | Group | — |
LIST_GROUPS (16) | Describe | Cluster | 无权限不报错,回退逐组检查。 |
LIST_GROUPS (16) | Describe | Group | 全未授权时返回空(自 2.1 起)。 |
SASL_HANDSHAKE (17) | — | — | 认证流程,无法授权。 |
API_VERSIONS (18) | — | — | 握手流程,无法授权。 |
CREATE_TOPICS (19) | Create | Cluster | 无集群级时回退 Topic 级并据此报错。 |
CREATE_TOPICS (19) | Create | Topic | 自 2.0 起。 |
DELETE_TOPICS (20) | Delete | Topic | — |
DELETE_RECORDS (21) | Delete | Topic | — |
INIT_PRODUCER_ID (22) | Write | TransactionalId | — |
INIT_PRODUCER_ID (22) | IdempotentWrite | Cluster | — |
OFFSET_FOR_LEADER_EPOCH (23) | ClusterAction | Cluster | 无集群级则查 Topic 级。 |
OFFSET_FOR_LEADER_EPOCH (23) | Describe | Topic | 自 2.1 起。 |
ADD_PARTITIONS_TO_TXN (24) | Write | TransactionalId | 仅事务请求;先 TxnId 后 Topic。 |
ADD_PARTITIONS_TO_TXN (24) | Write | Topic | — |
ADD_OFFSETS_TO_TXN (25) | Write | TransactionalId | 仅事务请求;先 TxnId 后 Group。 |
ADD_OFFSETS_TO_TXN (25) | Read | Group | — |
END_TXN (26) | Write | TransactionalId | — |
WRITE_TXN_MARKERS (27) | Alter | Cluster | — |
WRITE_TXN_MARKERS (27) | ClusterAction | Cluster | — |
TXN_OFFSET_COMMIT (28) | Write | TransactionalId | — |
TXN_OFFSET_COMMIT (28) | Read | Group | — |
TXN_OFFSET_COMMIT (28) | Read | Topic | — |
DESCRIBE_ACLS (29) | Describe | Cluster | — |
CREATE_ACLS (30) | Alter | Cluster | — |
DELETE_ACLS (31) | Alter | Cluster | — |
DESCRIBE_CONFIGS (32) | DescribeConfigs | Cluster | 查 broker 配置时。 |
DESCRIBE_CONFIGS (32) | DescribeConfigs | Topic | 查 topic 配置时。 |
ALTER_CONFIGS (33) | AlterConfigs | Cluster | 改 broker 配置时。 |
ALTER_CONFIGS (33) | AlterConfigs | Topic | 改 topic 配置时。 |
ALTER_REPLICA_LOG_DIRS (34) | Alter | Cluster | — |
DESCRIBE_LOG_DIRS (35) | Describe | Cluster | 未授权返回空。 |
SASL_AUTHENTICATE (36) | — | — | 认证流程,无法授权。 |
CREATE_PARTITIONS (37) | Alter | Topic | — |
CREATE_DELEGATION_TOKEN (38) | — | — | 特殊规则,见 Delegation Tokens。 |
CREATE_DELEGATION_TOKEN (38) | CreateTokens | User | 允许为 User 创建委派令牌。 |
RENEW_DELEGATION_TOKEN (39) | — | — | 特殊规则。 |
EXPIRE_DELEGATION_TOKEN (40) | — | — | 特殊规则。 |
DESCRIBE_DELEGATION_TOKEN (41) | Describe | DelegationToken | 特殊规则。 |
DESCRIBE_DELEGATION_TOKEN (41) | DescribeTokens | User | 允许描述 User 的委派令牌。 |
DELETE_GROUPS (42) | Delete | Group | — |
ELECT_PREFERRED_LEADERS (43) | ClusterAction | Cluster | — |
INCREMENTAL_ALTER_CONFIGS (44) | AlterConfigs | Cluster | 改 broker 配置。 |
INCREMENTAL_ALTER_CONFIGS (44) | AlterConfigs | Topic | 改 topic 配置。 |
ALTER_PARTITION_REASSIGNMENTS (45) | Alter | Cluster | — |
LIST_PARTITION_REASSIGNMENTS (46) | Describe | Cluster | — |
OFFSET_DELETE (47) | Delete | Group | — |
OFFSET_DELETE (47) | Read | Topic | — |
DESCRIBE_CLIENT_QUOTAS (48) | DescribeConfigs | Cluster | — |
ALTER_CLIENT_QUOTAS (49) | AlterConfigs | Cluster | — |
DESCRIBE_USER_SCRAM_CREDENTIALS (50) | Describe | Cluster | — |
ALTER_USER_SCRAM_CREDENTIALS (51) | Alter | Cluster | — |
VOTE (52) | ClusterAction | Cluster | — |
BEGIN_QUORUM_EPOCH (53) | ClusterAction | Cluster | — |
END_QUORUM_EPOCH (54) | ClusterAction | Cluster | — |
DESCRIBE_QUORUM (55) | Describe | Cluster | — |
ALTER_PARTITION (56) | ClusterAction | Cluster | — |
UPDATE_FEATURES (57) | Alter | Cluster | — |
ENVELOPE (58) | ClusterAction | Cluster | — |
FETCH_SNAPSHOT (59) | ClusterAction | Cluster | — |
DESCRIBE_CLUSTER (60) | Describe | Cluster | — |
DESCRIBE_PRODUCERS (61) | Read | Topic | — |
BROKER_REGISTRATION (62) | ClusterAction | Cluster | — |
BROKER_HEARTBEAT (63) | ClusterAction | Cluster | — |
UNREGISTER_BROKER (64) | Alter | Cluster | — |
DESCRIBE_TRANSACTIONS (65) | Describe | TransactionalId | — |
LIST_TRANSACTIONS (66) | Describe | TransactionalId | — |
ALLOCATE_PRODUCER_IDS (67) | ClusterAction | Cluster | — |
CONSUMER_GROUP_HEARTBEAT (68) | Read | Group | — |
CONSUMER_GROUP_DESCRIBE (69) | Read | Group | — |
CONTROLLER_REGISTRATION (70) | ClusterAction | Cluster | — |
GET_TELEMETRY_SUBSCRIPTIONS (71) | — | — | 无授权检查。 |
PUSH_TELEMETRY (72) | — | — | 无授权检查。 |
ASSIGN_REPLICAS_TO_DIRS (73) | ClusterAction | Cluster | — |
LIST_CONFIG_RESOURCES (74) | DescribeConfigs | Cluster | — |
DESCRIBE_TOPIC_PARTITIONS (75) | Describe | Topic | — |
SHARE_GROUP_HEARTBEAT (76) | Read | Group | — |
SHARE_GROUP_DESCRIBE (77) | Describe | Group | — |
SHARE_FETCH (78) | Read | Group | — |
SHARE_FETCH (78) | Read | Topic | — |
SHARE_ACKNOWLEDGE (79) | Read | Group | — |
SHARE_ACKNOWLEDGE (79) | Read | Topic | — |
INITIALIZE_SHARE_GROUP_STATE (83) | ClusterAction | Cluster | — |
READ_SHARE_GROUP_STATE (84) | ClusterAction | Cluster | — |
WRITE_SHARE_GROUP_STATE (85) | ClusterAction | Cluster | — |
DELETE_SHARE_GROUP_STATE (86) | ClusterAction | Cluster | — |
READ_SHARE_GROUP_STATE_SUMMARY (87) | ClusterAction | Cluster | — |
STREAMS_GROUP_HEARTBEAT (88) | Read | Group | — |
STREAMS_GROUP_HEARTBEAT (88) | Describe | Topic | 需要对所有源主题与内部主题授权。 |
STREAMS_GROUP_HEARTBEAT (88) | Create | Topic | 允许 broker 自动创建内部主题(若不存在)。 |
STREAMS_GROUP_DESCRIBE (89) | Describe | Group | — |
STREAMS_GROUP_DESCRIBE (89) | Describe | Topic | 需要对所有源/内部主题授权。 |
DESCRIBE_SHARE_GROUP_OFFSETS (90) | Describe | Group | 先组后题。 |
DESCRIBE_SHARE_GROUP_OFFSETS (90) | Describe | Topic | — |
ALTER_SHARE_GROUP_OFFSETS (91) | Read | Group | 先组后题。 |
ALTER_SHARE_GROUP_OFFSETS (91) | Read | Topic | — |
DELETE_SHARE_GROUP_OFFSETS (92) | Delete | Group | 先组后题。 |
DELETE_SHARE_GROUP_OFFSETS (92) | Read | Topic | — |
八、工程落地:最小权限、命名规范与排错清单
1)最小权限策略(示例)
- 生产者(普通):
Write@Topic:<t>
+ (如需)IdempotentWrite@Cluster
- 消费者(普通):
Read@Topic:<t>
+Read@Group:<g>
- 事务生产者:
Write@TransactionalId:<txid>
+Write@Topic:<t>
(以及必要时的 IdempotentWrite@Cluster) - Streams:为所有源主题与内部主题赋
Describe@Topic
;若允许自动创建内部主题,再赋Create@Topic
(或事先创建并仅给 Describe)
2)主体与主机规则
- 优先用 短名(SSL/SASL 映射)避免 DN/Realm/大小写问题。
--allow-host
/--deny-host
仅支持 IP;如需按网段限制,建议运维层控制或生成工具扩展。
3)资源模式
- **精确(literal)**用于“按名授权”,**通配(‘*’)**慎用。
- **前缀(prefixed)**适合多租户/批量主题,但需严格命名规范与审计。
- 清理 ACL 时避免盲用
--remove --resource-pattern-type match
。
4)“无 ACL”策略开关
- 默认拒绝安全性更高;若开启
allow.everyone.if.no.acl.found=true
,务必配合 CI/CD 审计防止“漏配即放开”。
5)KRaft Principal 转发
- 定制 principal 时记得实现
KafkaPrincipalSerde
;否则 Envelope 上下游序列化失败。
6)故障排查
- 错误码定位:
TOPIC_AUTHORIZATION_FAILED(29)
、GROUP_AUTHORIZATION_FAILED(30)
、CLUSTER_AUTHORIZATION_FAILED(31)
、TRANSACTIONAL_ID_AUTHORIZATION_FAILED(53)
。 - 若
LIST_GROUPS
返回空但不报错,考虑是权限不足导致的空集合(2.1+ 行为)。
九、运维脚本模板(占位符示例)
将
<BS>
、<TOPIC>
、<GROUP>
、<USER>
替换为实际值。
# Producer (literal)
bin/kafka-acls.sh --bootstrap-server <BS> --add \--allow-principal User:<USER> --producer --topic <TOPIC># Consumer (literal)
bin/kafka-acls.sh --bootstrap-server <BS> --add \--allow-principal User:<USER> --consumer --topic <TOPIC> --group <GROUP># Idempotent Producer (cluster-level)
bin/kafka-acls.sh --bootstrap-server <BS> --add \--allow-principal User:<USER> --operation IdempotentWrite --cluster# Streams 内部主题自动创建(前缀)
bin/kafka-acls.sh --bootstrap-server <BS> --add \--allow-principal User:<USER> --operation Create \--topic <INTERNAL_PREFIX> --resource-pattern-type prefixed
十、结语
本文按 KRaft 语义与官方结构,提供了 Kafka 授权体系的 全量知识面:从 Authorizer 启用、无 ACL 策略、super users,到 Envelope 转发与 principal 序列化契约;从 SSL/SASL 用户名映射的正则规则到 CLI 全参;再到覆盖 Streams/事务/共享组在内的 协议×操作×资源矩阵。