ZooKeeper ACL 权限控制机制深度解析:从原理到实战
-
- 一、ACL 权限控制概述
-
- 1.1 什么是 ACL?
- 1.2 为什么需要 ACL?
- 二、ACL 的组成要素
-
- 2.1 权限类型(Permissions)
- 2.2 认证方案(Scheme)
- 三、ACL 的工作流程
-
- 3.1 完整的 ACL 验证流程
- 3.2 权限验证的核心逻辑
- 四、内置 ACL 常量
- 五、ACL 的操作命令
-
- 5.1 命令行操作
-
- 添加认证信息
- 查看 ACL
- 设置 ACL
- 创建时直接设置 ACL
- 5.2 Java API 操作
-
- 客户端添加认证信息
- 六、五种认证方案详解
-
- 6.1 world 方案:最简单但最不安全
- 6.2 auth 方案:当前认证用户
- 6.3 digest 方案:最常用
-
- 密码哈希生成工具
- 使用示例
- 6.4 ip 方案:基于网络位置
- 6.5 sasl 方案:企业级认证
- 七、ACL 的继承规则与注意事项
-
- 7.1 ACL 的继承规则
- 7.2 重要注意事项
- 八、最佳实践与安全建议
-
- 8.1 生产环境 ACL 配置清单
- 8.2 常见场景配置
- 8.3 安全审计脚本
- 九、总结
-
- 9.1 ACL 核心要点
- 9.2 实现原理回顾
- 9.3 一句话总结
|
🌺The Begin🌺点点关注,收藏不迷路🌺 |
摘要:在分布式系统中,数据安全是至关重要的。ZooKeeper 作为分布式协调服务,存储着大量敏感配置和元数据,必须提供完善的访问控制机制。ACL(Access Control List,访问控制列表)就是 ZooKeeper 实现精细化权限管理的核心机制。本文将深入剖析 ZooKeeper ACL 的工作原理、权限类型、认证方案以及完整的实现流程,通过源码分析和实战示例,帮助读者全面掌握 ACL 权限控制机制。
一、ACL 权限控制概述
1.1 什么是 ACL?
ACL(Access Control List)是 ZooKeeper 提供的访问控制列表机制,用于定义谁可以对 ZNode 执行什么操作 。它与传统的 UNIX 文件权限类似,但更加灵活和精细化,主要体现在:
- 没有文件所有者概念:不同于 UNIX 权限中的用户(owner)、组(group)、其他人(other)三范围,ZooKeeper 的节点没有所有者的概念
- 支持多种认证方案:通过可插拔的认证机制,支持 world、auth、digest、ip、sasl 等多种认证方式
- 节点级控制:ACL 仅针对特定节点,不会递归应用到子节点
#mermaid-svg-S5RtMackONuFdRjP{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-S5RtMackONuFdRjP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-S5RtMackONuFdRjP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-S5RtMackONuFdRjP .error-icon{fill:#552222;}#mermaid-svg-S5RtMackONuFdRjP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-S5RtMackONuFdRjP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-S5RtMackONuFdRjP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S5RtMackONuFdRjP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S5RtMackONuFdRjP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-S5RtMackONuFdRjP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S5RtMackONuFdRjP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S5RtMackONuFdRjP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-S5RtMackONuFdRjP .marker.cross{stroke:#333333;}#mermaid-svg-S5RtMackONuFdRjP svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S5RtMackONuFdRjP p{margin:0;}#mermaid-svg-S5RtMackONuFdRjP .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-S5RtMackONuFdRjP .cluster-label text{fill:#333;}#mermaid-svg-S5RtMackONuFdRjP .cluster-label span{color:#333;}#mermaid-svg-S5RtMackONuFdRjP .cluster-label span p{background-color:transparent;}#mermaid-svg-S5RtMackONuFdRjP .label text,#mermaid-svg-S5RtMackONuFdRjP span{fill:#333;color:#333;}#mermaid-svg-S5RtMackONuFdRjP .node rect,#mermaid-svg-S5RtMackONuFdRjP .node circle,#mermaid-svg-S5RtMackONuFdRjP .node ellipse,#mermaid-svg-S5RtMackONuFdRjP .node polygon,#mermaid-svg-S5RtMackONuFdRjP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-S5RtMackONuFdRjP .rough-node .label text,#mermaid-svg-S5RtMackONuFdRjP .node .label text,#mermaid-svg-S5RtMackONuFdRjP .image-shape .label,#mermaid-svg-S5RtMackONuFdRjP .icon-shape .label{text-anchor:middle;}#mermaid-svg-S5RtMackONuFdRjP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-S5RtMackONuFdRjP .rough-node .label,#mermaid-svg-S5RtMackONuFdRjP .node .label,#mermaid-svg-S5RtMackONuFdRjP .image-shape .label,#mermaid-svg-S5RtMackONuFdRjP .icon-shape .label{text-align:center;}#mermaid-svg-S5RtMackONuFdRjP .node.clickable{cursor:pointer;}#mermaid-svg-S5RtMackONuFdRjP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-S5RtMackONuFdRjP .arrowheadPath{fill:#333333;}#mermaid-svg-S5RtMackONuFdRjP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-S5RtMackONuFdRjP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-S5RtMackONuFdRjP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S5RtMackONuFdRjP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-S5RtMackONuFdRjP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S5RtMackONuFdRjP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-S5RtMackONuFdRjP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-S5RtMackONuFdRjP .cluster text{fill:#333;}#mermaid-svg-S5RtMackONuFdRjP .cluster span{color:#333;}#mermaid-svg-S5RtMackONuFdRjP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-S5RtMackONuFdRjP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-S5RtMackONuFdRjP rect.text{fill:none;stroke-width:0;}#mermaid-svg-S5RtMackONuFdRjP .icon-shape,#mermaid-svg-S5RtMackONuFdRjP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S5RtMackONuFdRjP .icon-shape p,#mermaid-svg-S5RtMackONuFdRjP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-S5RtMackONuFdRjP .icon-shape rect,#mermaid-svg-S5RtMackONuFdRjP .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S5RtMackONuFdRjP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-S5RtMackONuFdRjP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-S5RtMackONuFdRjP :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
ACL 的核心组成
ACL
Scheme授权方案
ID授权ID
Permissions权限位
1.2 为什么需要 ACL?
ZooKeeper 中存储着大量敏感信息 :
| 配置信息 | 数据库连接串、密码、密钥 | 泄露导致数据被篡改 |
| 服务元数据 | 服务注册信息、路由规则 | 恶意服务注册导致流量劫持 |
| 分布式锁 | 锁节点状态 | 误释放或抢占锁导致数据竞争 |
| 集群状态 | 节点存活信息 | 暴露内部拓扑结构 |
没有 ACL,任何客户端都可以随意读取、修改这些数据,造成严重的安全隐患。
二、ACL 的组成要素
每个 ACL 由三部分组成:权限(permissions)、认证方案(scheme)和授权ID(id) 。
2.1 权限类型(Permissions)
ZooKeeper 定义了 5 种基本权限,使用字母表示,可以组合使用 :
| CREATE | c | 1 | 允许创建子节点 |
| DELETE | d | 2 | 允许删除子节点 |
| READ | r | 4 | 允许读取节点数据及子节点列表 |
| WRITE | w | 8 | 允许修改节点数据 |
| ADMIN | a | 16 | 允许设置 ACL 权限 |
权限设计背后的考量:
- CREATE 和 DELETE 从 WRITE 权限中分离出来,是为了更精细的控制 。例如:
- 你可以允许用户设置节点数据,但不允许创建或删除子节点
- 有 CREATE 但无 DELETE 权限:客户端可以创建节点,但只有特定进程能删除(类似于文件的 APPEND 权限)
权限组合示例:
// 权限组合计算
int READ_WRITE = 4 | 8 = 12; // rw
int ALL = 1 | 2 | 4 | 8 | 16 = 31; // cdwra
int READ_ONLY = 4; // r
#mermaid-svg-hli577Pr4CFba3xz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hli577Pr4CFba3xz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hli577Pr4CFba3xz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hli577Pr4CFba3xz .error-icon{fill:#552222;}#mermaid-svg-hli577Pr4CFba3xz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hli577Pr4CFba3xz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hli577Pr4CFba3xz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hli577Pr4CFba3xz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hli577Pr4CFba3xz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hli577Pr4CFba3xz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hli577Pr4CFba3xz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hli577Pr4CFba3xz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hli577Pr4CFba3xz .marker.cross{stroke:#333333;}#mermaid-svg-hli577Pr4CFba3xz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hli577Pr4CFba3xz p{margin:0;}#mermaid-svg-hli577Pr4CFba3xz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-hli577Pr4CFba3xz .cluster-label text{fill:#333;}#mermaid-svg-hli577Pr4CFba3xz .cluster-label span{color:#333;}#mermaid-svg-hli577Pr4CFba3xz .cluster-label span p{background-color:transparent;}#mermaid-svg-hli577Pr4CFba3xz .label text,#mermaid-svg-hli577Pr4CFba3xz span{fill:#333;color:#333;}#mermaid-svg-hli577Pr4CFba3xz .node rect,#mermaid-svg-hli577Pr4CFba3xz .node circle,#mermaid-svg-hli577Pr4CFba3xz .node ellipse,#mermaid-svg-hli577Pr4CFba3xz .node polygon,#mermaid-svg-hli577Pr4CFba3xz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hli577Pr4CFba3xz .rough-node .label text,#mermaid-svg-hli577Pr4CFba3xz .node .label text,#mermaid-svg-hli577Pr4CFba3xz .image-shape .label,#mermaid-svg-hli577Pr4CFba3xz .icon-shape .label{text-anchor:middle;}#mermaid-svg-hli577Pr4CFba3xz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hli577Pr4CFba3xz .rough-node .label,#mermaid-svg-hli577Pr4CFba3xz .node .label,#mermaid-svg-hli577Pr4CFba3xz .image-shape .label,#mermaid-svg-hli577Pr4CFba3xz .icon-shape .label{text-align:center;}#mermaid-svg-hli577Pr4CFba3xz .node.clickable{cursor:pointer;}#mermaid-svg-hli577Pr4CFba3xz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hli577Pr4CFba3xz .arrowheadPath{fill:#333333;}#mermaid-svg-hli577Pr4CFba3xz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hli577Pr4CFba3xz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hli577Pr4CFba3xz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hli577Pr4CFba3xz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hli577Pr4CFba3xz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hli577Pr4CFba3xz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hli577Pr4CFba3xz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hli577Pr4CFba3xz .cluster text{fill:#333;}#mermaid-svg-hli577Pr4CFba3xz .cluster span{color:#333;}#mermaid-svg-hli577Pr4CFba3xz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hli577Pr4CFba3xz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hli577Pr4CFba3xz rect.text{fill:none;stroke-width:0;}#mermaid-svg-hli577Pr4CFba3xz .icon-shape,#mermaid-svg-hli577Pr4CFba3xz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hli577Pr4CFba3xz .icon-shape p,#mermaid-svg-hli577Pr4CFba3xz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hli577Pr4CFba3xz .icon-shape rect,#mermaid-svg-hli577Pr4CFba3xz .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hli577Pr4CFba3xz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hli577Pr4CFba3xz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hli577Pr4CFba3xz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
常见权限组合
权限组合 (按位或运算)
ZooKeeper ACL 权限位定义
CREATE (C)位值: 1 (2^0)
DELETE (D)位值: 2 (2^1)
READ (R)位值: 4 (2^2)
WRITE (W)位值: 8 (2^3)
ADMIN (A)位值: 16 (2^4)
权限组合
cdwr (15)CREATE|DELETE|READ|WRITE1|2|4|8 = 15
rwa (28)READ|WRITE|ADMIN4|8|16 = 28
all (31)所有权限1|2|4|8|16 = 31
read (4)只读权限READ = 4
write (8)只写权限WRITE = 8
2.2 认证方案(Scheme)
Scheme 定义了 ACL 的验证方式,ZooKeeper 支持多种方案 :
| world | 全世界,所有客户端都有权限 | anyone | 公开数据、默认配置 |
| auth | 任何已认证的用户 | 空(使用当前认证信息) | 多用户协作 |
| digest | 用户名:密码认证 | 用户名:密码哈希 | 最常见的认证方式 |
| ip | IP 地址限制 | IP 地址或网段 | 内网服务、固定IP环境 |
| sasl | Kerberos 认证 | 认证主体 | 企业级安全环境 |
特别说明 :
- 由于普通模式启动客户端不需要认证,sasl 认证类型的 ACL 在普通模式下将不能使用
- 在 3.5.6 及以后版本,用户对于 getAcl 操作需要有读权限
三、ACL 的工作流程
3.1 完整的 ACL 验证流程
Client2
ACL验证模块
认证模块
ZooKeeper服务器
客户端
Client2
ACL验证模块
认证模块
ZooKeeper服务器
客户端
#mermaid-svg-q1Y3B9USA5KmIRF1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-q1Y3B9USA5KmIRF1 .error-icon{fill:#552222;}#mermaid-svg-q1Y3B9USA5KmIRF1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-q1Y3B9USA5KmIRF1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-q1Y3B9USA5KmIRF1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-q1Y3B9USA5KmIRF1 .marker.cross{stroke:#333333;}#mermaid-svg-q1Y3B9USA5KmIRF1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-q1Y3B9USA5KmIRF1 p{margin:0;}#mermaid-svg-q1Y3B9USA5KmIRF1 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-q1Y3B9USA5KmIRF1 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-q1Y3B9USA5KmIRF1 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-q1Y3B9USA5KmIRF1 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-q1Y3B9USA5KmIRF1 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-q1Y3B9USA5KmIRF1 .sequenceNumber{fill:white;}#mermaid-svg-q1Y3B9USA5KmIRF1 #sequencenumber{fill:#333;}#mermaid-svg-q1Y3B9USA5KmIRF1 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-q1Y3B9USA5KmIRF1 .messageText{fill:#333;stroke:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-q1Y3B9USA5KmIRF1 .labelText,#mermaid-svg-q1Y3B9USA5KmIRF1 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .loopText,#mermaid-svg-q1Y3B9USA5KmIRF1 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-q1Y3B9USA5KmIRF1 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-q1Y3B9USA5KmIRF1 .noteText,#mermaid-svg-q1Y3B9USA5KmIRF1 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-q1Y3B9USA5KmIRF1 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-q1Y3B9USA5KmIRF1 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-q1Y3B9USA5KmIRF1 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-q1Y3B9USA5KmIRF1 .actorPopupMenu{position:absolute;}#mermaid-svg-q1Y3B9USA5KmIRF1 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-q1Y3B9USA5KmIRF1 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-q1Y3B9USA5KmIRF1 .actor-man circle,#mermaid-svg-q1Y3B9USA5KmIRF1 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-q1Y3B9USA5KmIRF1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
阶段1:添加认证信息
阶段2:创建受保护节点
阶段3:未认证的访问
阶段4:已认证的访问
addauth digest user:pass
验证用户名密码
认证通过,存储认证信息
create /secure secret
设置 ACL: digest:user:pass:cdwra
创建成功
get /secure
检查客户端认证信息
无匹配认证信息
NoAuth异常
get /secure
检查客户端认证信息
认证匹配,权限通过
返回数据
3.2 权限验证的核心逻辑
当客户端请求访问 ZNode 时,ZooKeeper 按照以下规则进行权限验证 :
// 权限验证的核心逻辑(简化版)
public boolean checkPermission(ClientInfo client, ZNode node, int requiredPerm) {
// 1. 获取节点的 ACL 列表
List<ACL> acls = node.getAcl();
// 2. 遍历 ACL,查找匹配项
for (ACL acl : acls) {
// 检查 scheme 是否匹配
if (!matchesScheme(client, acl)) continue;
// 检查 ID 是否匹配
if (!matchesId(client, acl)) continue;
// 检查权限是否包含所需权限
if ((acl.getPerms() & requiredPerm) == requiredPerm) {
return true; // 权限验证通过
}
}
// 3. 没有匹配的 ACL,拒绝访问
return false;
}
四、内置 ACL 常量
ZooKeeper 在 ZooDefs.Ids 中提供了一些常用的 ACL 常量,方便开发者使用 :
| OPEN_ACL_UNSAFE | world:anyone:cdrwa | 完全开放,任何应用可在节点上执行任何操作,能创建、列出和删除其子节点 |
| CREATOR_ALL_ACL | auth::cdrwa | 创建者有所有权限,创建者必须已被服务器认证 |
| READ_ACL_UNSAFE | world:anyone:r | 任何人只读 |
public class BuiltInAclExample {
public void useBuiltInAcl() throws Exception {
ZooKeeper zk = new ZooKeeper("localhost:2181", 5000, null);
// 1. 完全开放的节点(不安全)
zk.create("/public", "data".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
// 2. 仅创建者可访问
zk.addAuthInfo("digest", "admin:admin123".getBytes());
zk.create("/private", "secret".getBytes(),
ZooDefs.Ids.CREATOR_ALL_ACL,
CreateMode.PERSISTENT);
// 3. 全局只读
zk.create("/readonly", "readme".getBytes(),
ZooDefs.Ids.READ_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
}
五、ACL 的操作命令
5.1 命令行操作
添加认证信息
# 添加 digest 认证信息
[zk: localhost:2181(CONNECTED) 0] addauth digest admin:admin123
查看 ACL
# 查看节点的 ACL
[zk: localhost:2181(CONNECTED) 1] getAcl /config
# 输出示例
'world,'anyone
: cdrwa
设置 ACL
# 1. world 方案(任何人可读)
[zk: localhost:2181(CONNECTED) 0] create /public "public-data"
[zk: localhost:2181(CONNECTED) 1] setAcl /public world:anyone:r
# 2. digest 方案(用户名密码认证)
[zk: localhost:2181(CONNECTED) 2] addauth digest admin:admin123
[zk: localhost:2181(CONNECTED) 3] create /secure "secret"
[zk: localhost:2181(CONNECTED) 4] setAcl /secure digest:admin:admin123:cdwra
# 3. ip 方案(IP 限制)
[zk: localhost:2181(CONNECTED) 5] create /ip-limited "internal"
[zk: localhost:2181(CONNECTED) 6] setAcl /ip-limited ip:192.168.1.0/24:cdrwa
# 4. 组合多个 ACL
[zk: localhost:2181(CONNECTED) 7] setAcl /multi world:anyone:r,digest:admin:admin123:cdwra
创建时直接设置 ACL
# 创建节点时指定 ACL
[zk: localhost:2181(CONNECTED) 0] create /secure-node "data" digest:admin:admin123:cdwra
5.2 Java API 操作
客户端添加认证信息
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
import java.util.ArrayList;
import java.util.List;
public class ACLExample {
private ZooKeeper zk;
/**
* 添加认证信息
*/
public void addAuth() throws Exception {
// 添加 digest 认证
zk.addAuthInfo("digest", "admin:admin123".getBytes());
System.out.println("认证信息已添加");
}
/**
* 创建带 ACL 的节点
*/
public void createNodeWithAcl() throws Exception {
// 1. 添加认证信息(必须先认证)
zk.addAuthInfo("digest", "admin:admin123".getBytes());
// 2. 创建 ACL 列表
List<ACL> acls = new ArrayList<>();
// 添加 digest 认证 ACL
Id id1 = new Id("digest", "admin:W5R8ZqN7nYqY9YqY"); // 密码哈希
acls.add(new ACL(ZooDefs.Perms.ALL, id1)); // 所有权限
// 添加 IP 限制 ACL
Id id2 = new Id("ip", "192.168.1.100");
acls.add(new ACL(ZooDefs.Perms.READ, id2)); // 只读权限
// 3. 创建节点
String path = zk.create("/secure-node",
"sensitive-data".getBytes(),
acls,
CreateMode.PERSISTENT);
System.out.println("节点创建成功: " + path);
}
/**
* 获取节点的 ACL
*/
public void getNodeAcl(String path) throws Exception {
Stat stat = new Stat();
List<ACL> acls = zk.getACL(path, stat);
System.out.println("节点 " + path + " 的 ACL:");
for (ACL acl : acls) {
System.out.println(" Scheme: " + acl.getId().getScheme() +
", ID: " + acl.getId().getId() +
", Perms: " + acl.getPerms());
}
}
/**
* 设置节点的 ACL
*/
public void setNodeAcl(String path) throws Exception {
// 创建新的 ACL
List<ACL> acls = ZooDefs.Ids.CREATOR_ALL_ACL; // 仅创建者有所有权限
Stat stat = new Stat();
zk.getData(path, false, stat);
// 使用版本号更新 ACL(aversion 版本控制)
zk.setACL(path, acls, stat.getAversion());
System.out.println("ACL 更新成功");
}
}
六、五种认证方案详解
6.1 world 方案:最简单但最不安全
# world 方案
[zk: localhost:2181(CONNECTED) 0] create /public "open"
[zk: localhost:2181(CONNECTED) 1] setAcl /public world:anyone:r
# 任何人都可以读
[zk: localhost:2181(CONNECTED) 2] get /public
open
特点 :
- 不进行任何认证
- ID 固定为 anyone
- 适合公开的配置信息
6.2 auth 方案:当前认证用户
# 1. 先添加认证
[zk: localhost:2181(CONNECTED) 0] addauth digest user1:pass1
[zk: localhost:2181(CONNECTED) 1] addauth digest user2:pass2
# 2. 创建节点,使用 auth 方案
[zk: localhost:2181(CONNECTED) 2] create /shared "shared-data"
[zk: localhost:2181(CONNECTED) 3] setAcl /shared auth::cdrwa
# 3. 查看 ACL(自动添加了两个用户)
[zk: localhost:2181(CONNECTED) 4] getAcl /shared
'digest,'user1:rX8ZpK6mXpX8XpX
: cdrwa
'digest,'user2:pY7QoJ5nYoY7YoY
: cdrwa
特点 :
- 自动将当前所有已认证用户添加到 ACL
- ID 为空字符串,表示"创建者的身份"
- 适合多用户协作场景
6.3 digest 方案:最常用
digest 认证通过用户名和密码进行身份验证,是生产环境中最常用的认证方式。密码不以明文存储,而是经过 SHA-1 加密后再进行 Base64 编码 。
#mermaid-svg-bPXEq6cfToDFe02r{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bPXEq6cfToDFe02r .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bPXEq6cfToDFe02r .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bPXEq6cfToDFe02r .error-icon{fill:#552222;}#mermaid-svg-bPXEq6cfToDFe02r .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bPXEq6cfToDFe02r .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bPXEq6cfToDFe02r .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bPXEq6cfToDFe02r .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bPXEq6cfToDFe02r .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bPXEq6cfToDFe02r .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bPXEq6cfToDFe02r .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bPXEq6cfToDFe02r .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bPXEq6cfToDFe02r .marker.cross{stroke:#333333;}#mermaid-svg-bPXEq6cfToDFe02r svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bPXEq6cfToDFe02r p{margin:0;}#mermaid-svg-bPXEq6cfToDFe02r .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-bPXEq6cfToDFe02r .cluster-label text{fill:#333;}#mermaid-svg-bPXEq6cfToDFe02r .cluster-label span{color:#333;}#mermaid-svg-bPXEq6cfToDFe02r .cluster-label span p{background-color:transparent;}#mermaid-svg-bPXEq6cfToDFe02r .label text,#mermaid-svg-bPXEq6cfToDFe02r span{fill:#333;color:#333;}#mermaid-svg-bPXEq6cfToDFe02r .node rect,#mermaid-svg-bPXEq6cfToDFe02r .node circle,#mermaid-svg-bPXEq6cfToDFe02r .node ellipse,#mermaid-svg-bPXEq6cfToDFe02r .node polygon,#mermaid-svg-bPXEq6cfToDFe02r .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bPXEq6cfToDFe02r .rough-node .label text,#mermaid-svg-bPXEq6cfToDFe02r .node .label text,#mermaid-svg-bPXEq6cfToDFe02r .image-shape .label,#mermaid-svg-bPXEq6cfToDFe02r .icon-shape .label{text-anchor:middle;}#mermaid-svg-bPXEq6cfToDFe02r .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bPXEq6cfToDFe02r .rough-node .label,#mermaid-svg-bPXEq6cfToDFe02r .node .label,#mermaid-svg-bPXEq6cfToDFe02r .image-shape .label,#mermaid-svg-bPXEq6cfToDFe02r .icon-shape .label{text-align:center;}#mermaid-svg-bPXEq6cfToDFe02r .node.clickable{cursor:pointer;}#mermaid-svg-bPXEq6cfToDFe02r .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bPXEq6cfToDFe02r .arrowheadPath{fill:#333333;}#mermaid-svg-bPXEq6cfToDFe02r .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bPXEq6cfToDFe02r .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bPXEq6cfToDFe02r .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bPXEq6cfToDFe02r .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bPXEq6cfToDFe02r .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bPXEq6cfToDFe02r .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bPXEq6cfToDFe02r .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bPXEq6cfToDFe02r .cluster text{fill:#333;}#mermaid-svg-bPXEq6cfToDFe02r .cluster span{color:#333;}#mermaid-svg-bPXEq6cfToDFe02r div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bPXEq6cfToDFe02r .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bPXEq6cfToDFe02r rect.text{fill:none;stroke-width:0;}#mermaid-svg-bPXEq6cfToDFe02r .icon-shape,#mermaid-svg-bPXEq6cfToDFe02r .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bPXEq6cfToDFe02r .icon-shape p,#mermaid-svg-bPXEq6cfToDFe02r .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bPXEq6cfToDFe02r .icon-shape rect,#mermaid-svg-bPXEq6cfToDFe02r .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bPXEq6cfToDFe02r .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bPXEq6cfToDFe02r .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bPXEq6cfToDFe02r :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
digest 认证流程
匹配
不匹配
客户端输入用户名:密码
addauth digest user:pass
客户端发送明文密码
服务端计算 SHA-1 哈希
与存储的哈希比较
认证通过
认证失败
密码哈希生成工具
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
public class PasswordGenerator {
public static void main(String[] args) throws Exception {
String userPass = "admin:admin123";
String hash = DigestAuthenticationProvider.generateDigest(userPass);
System.out.println("密码哈希: " + hash);
// 输出: admin:W5R8ZqN7nYqY9YqY
}
}
使用示例
# 1. 添加认证
[zk: localhost:2181(CONNECTED) 0] addauth digest admin:admin123
# 2. 创建受保护节点
[zk: localhost:2181(CONNECTED) 1] create /secret "top-secret"
[zk: localhost:2181(CONNECTED) 2] setAcl /secret digest:admin:admin123:cdwra
# 3. 查看 ACL(密码已哈希)
[zk: localhost:2181(CONNECTED) 3] getAcl /secret
'digest,'admin:W5R8ZqN7nYqY9YqY
: cdrwa
# 4. 另一个客户端尝试访问
[zk: localhost:2181(CONNECTED) 0] get /secret
KeeperErrorCode = NoAuth for /secret
# 5. 添加正确认证后可以访问
[zk: localhost:2181(CONNECTED) 1] addauth digest admin:admin123
[zk: localhost:2181(CONNECTED) 2] get /secret
top-secret
6.4 ip 方案:基于网络位置
# 允许特定 IP 访问
[zk: localhost:2181(CONNECTED) 0] create /internal "internal-data"
[zk: localhost:2181(CONNECTED) 1] setAcl /internal ip:192.168.1.100:cdrwa
# 允许整个网段
[zk: localhost:2181(CONNECTED) 2] setAcl /internal ip:192.168.1.0/24:cdrwa
特点 :
- 基于客户端 IP 地址认证
- 可以指定单个 IP 或 CIDR 网段(如 ip:19.22.0.0/16)
- 适合内部网络服务
6.5 sasl 方案:企业级认证
sasl(Simple Authentication and Security Layer)认证是 ZooKeeper 提供的最高安全级别的认证方式,基于 JAAS(Java Authentication and Authorization Service)框架,支持 Kerberos 等企业级认证协议 。
# zoo.cfg 中启用 SASL 认证
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
requireClientAuthScheme=sasl
jaasLoginRenew=3600000
# 使用 sasl 认证的 ACL
setAcl /secure sasl:userA@HADOOP.COM:cdrwa
七、ACL 的继承规则与注意事项
7.1 ACL 的继承规则
ZooKeeper 中,子节点不会自动继承父节点的 ACL。每个节点独立设置自己的 ACL 。
#mermaid-svg-DMpOz7LQtKkneIGq{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DMpOz7LQtKkneIGq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DMpOz7LQtKkneIGq .error-icon{fill:#552222;}#mermaid-svg-DMpOz7LQtKkneIGq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DMpOz7LQtKkneIGq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DMpOz7LQtKkneIGq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DMpOz7LQtKkneIGq .marker.cross{stroke:#333333;}#mermaid-svg-DMpOz7LQtKkneIGq svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DMpOz7LQtKkneIGq p{margin:0;}#mermaid-svg-DMpOz7LQtKkneIGq .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-DMpOz7LQtKkneIGq .cluster-label text{fill:#333;}#mermaid-svg-DMpOz7LQtKkneIGq .cluster-label span{color:#333;}#mermaid-svg-DMpOz7LQtKkneIGq .cluster-label span p{background-color:transparent;}#mermaid-svg-DMpOz7LQtKkneIGq .label text,#mermaid-svg-DMpOz7LQtKkneIGq span{fill:#333;color:#333;}#mermaid-svg-DMpOz7LQtKkneIGq .node rect,#mermaid-svg-DMpOz7LQtKkneIGq .node circle,#mermaid-svg-DMpOz7LQtKkneIGq .node ellipse,#mermaid-svg-DMpOz7LQtKkneIGq .node polygon,#mermaid-svg-DMpOz7LQtKkneIGq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DMpOz7LQtKkneIGq .rough-node .label text,#mermaid-svg-DMpOz7LQtKkneIGq .node .label text,#mermaid-svg-DMpOz7LQtKkneIGq .image-shape .label,#mermaid-svg-DMpOz7LQtKkneIGq .icon-shape .label{text-anchor:middle;}#mermaid-svg-DMpOz7LQtKkneIGq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DMpOz7LQtKkneIGq .rough-node .label,#mermaid-svg-DMpOz7LQtKkneIGq .node .label,#mermaid-svg-DMpOz7LQtKkneIGq .image-shape .label,#mermaid-svg-DMpOz7LQtKkneIGq .icon-shape .label{text-align:center;}#mermaid-svg-DMpOz7LQtKkneIGq .node.clickable{cursor:pointer;}#mermaid-svg-DMpOz7LQtKkneIGq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DMpOz7LQtKkneIGq .arrowheadPath{fill:#333333;}#mermaid-svg-DMpOz7LQtKkneIGq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DMpOz7LQtKkneIGq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DMpOz7LQtKkneIGq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DMpOz7LQtKkneIGq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DMpOz7LQtKkneIGq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DMpOz7LQtKkneIGq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DMpOz7LQtKkneIGq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DMpOz7LQtKkneIGq .cluster text{fill:#333;}#mermaid-svg-DMpOz7LQtKkneIGq .cluster span{color:#333;}#mermaid-svg-DMpOz7LQtKkneIGq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DMpOz7LQtKkneIGq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DMpOz7LQtKkneIGq rect.text{fill:none;stroke-width:0;}#mermaid-svg-DMpOz7LQtKkneIGq .icon-shape,#mermaid-svg-DMpOz7LQtKkneIGq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DMpOz7LQtKkneIGq .icon-shape p,#mermaid-svg-DMpOz7LQtKkneIGq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DMpOz7LQtKkneIGq .icon-shape rect,#mermaid-svg-DMpOz7LQtKkneIGq .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DMpOz7LQtKkneIGq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DMpOz7LQtKkneIGq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DMpOz7LQtKkneIGq :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
/parentACL: admin:cdrwa
/parent/child1ACL: world:r
/parent/child2ACL: auth::cdw
# 验证继承规则
[zk: localhost:2181(CONNECTED) 0] create /parent "parent"
[zk: localhost:2181(CONNECTED) 1] setAcl /parent digest:admin:admin123:cdrwa
[zk: localhost:2181(CONNECTED) 2] create /parent/child "child"
[zk: localhost:2181(CONNECTED) 3] getAcl /parent/child
'world,'anyone
: cdrwa # 子节点使用默认 ACL,没有继承父节点
7.2 重要注意事项
| ACL 不是递归的 | 父节点的 ACL 不适用于子节点 | /app 可被 IP 访问,/app/status 可能对所有人开放 |
| ADMIN 权限的特殊性 | 由于没有文件所有者概念,ADMIN 权限在某种意义上指定了"所有者" | 只有具有 ADMIN 权限的客户端才能修改 ACL |
| 隐含的 LOOKUP 权限 | 所有用户隐式具有 LOOKUP 权限,可以 stat 节点,但不能做其他操作 | 即使没有 READ 权限,也可以检查节点是否存在 |
| 版本控制 | 修改 ACL 时需注意 aversion 版本号 | 使用版本号防止并发修改冲突 |
八、最佳实践与安全建议
8.1 生产环境 ACL 配置清单
✅ 禁用 world 认证,除非必要
✅ 使用 digest 认证作为默认方案
✅ 密码遵循复杂度要求
✅ 结合 IP 限制增强安全
✅ 开启 SASL 用于高安全场景
✅ 审计认证失败日志
✅ 定期检查 ACL 配置
8.2 常见场景配置
| 公共配置 | world:anyone:r | 所有人可读,不可写 |
| 服务注册 | auth::cd | 已认证服务可创建删除 |
| 敏感配置 | digest:admin:cdrwa | 只有管理员可访问 |
| 内部服务 | ip:10.0.0.0/8:r | 仅内网可读 |
8.3 安全审计脚本
#!/bin/bash
# audit_zk_acl.sh – 审计 ZooKeeper ACL 配置
ZK_CLIENT="./zkCli.sh -server localhost:2181"
echo "===== ZooKeeper ACL 审计报告 ====="
echo "时间: $(date)"
echo ""
# 获取所有节点
nodes=$(echo "ls /" | $ZK_CLIENT 2>/dev/null | grep -v "WATCHER" | grep -v "Connecting" | tr -d '[],')
for node in $nodes; do
echo "节点: $node"
# 获取 ACL
acl=$(echo "getAcl $node" | $ZK_CLIENT 2>/dev/null | grep -v "WATCHER" | grep -v "Connecting")
# 检查是否存在开放权限
if echo "$acl" | grep -q "world:anyone:cdrwa"; then
echo "⚠️ 警告: 节点 $node 完全开放 (world:anyone:cdrwa)"
fi
# 检查是否有 ADMIN 权限滥用
if echo "$acl" | grep -q "a"; then
echo "ℹ️ 节点 $node 包含 ADMIN 权限"
fi
echo "ACL: $acl"
echo "—"
done
九、总结
9.1 ACL 核心要点
| 权限 | 5 种基本操作 | c,d,r,w,a |
| Scheme | 认证方式 | world,auth,digest,ip,sasl |
| ID | 具体标识 | anyone,用户名,IP地址,密码哈希 |
9.2 实现原理回顾
#mermaid-svg-gOgyR9BMQkpioQk7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gOgyR9BMQkpioQk7 .error-icon{fill:#552222;}#mermaid-svg-gOgyR9BMQkpioQk7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gOgyR9BMQkpioQk7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gOgyR9BMQkpioQk7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gOgyR9BMQkpioQk7 .marker.cross{stroke:#333333;}#mermaid-svg-gOgyR9BMQkpioQk7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gOgyR9BMQkpioQk7 p{margin:0;}#mermaid-svg-gOgyR9BMQkpioQk7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster-label text{fill:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster-label span{color:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster-label span p{background-color:transparent;}#mermaid-svg-gOgyR9BMQkpioQk7 .label text,#mermaid-svg-gOgyR9BMQkpioQk7 span{fill:#333;color:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 .node rect,#mermaid-svg-gOgyR9BMQkpioQk7 .node circle,#mermaid-svg-gOgyR9BMQkpioQk7 .node ellipse,#mermaid-svg-gOgyR9BMQkpioQk7 .node polygon,#mermaid-svg-gOgyR9BMQkpioQk7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gOgyR9BMQkpioQk7 .rough-node .label text,#mermaid-svg-gOgyR9BMQkpioQk7 .node .label text,#mermaid-svg-gOgyR9BMQkpioQk7 .image-shape .label,#mermaid-svg-gOgyR9BMQkpioQk7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-gOgyR9BMQkpioQk7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gOgyR9BMQkpioQk7 .rough-node .label,#mermaid-svg-gOgyR9BMQkpioQk7 .node .label,#mermaid-svg-gOgyR9BMQkpioQk7 .image-shape .label,#mermaid-svg-gOgyR9BMQkpioQk7 .icon-shape .label{text-align:center;}#mermaid-svg-gOgyR9BMQkpioQk7 .node.clickable{cursor:pointer;}#mermaid-svg-gOgyR9BMQkpioQk7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gOgyR9BMQkpioQk7 .arrowheadPath{fill:#333333;}#mermaid-svg-gOgyR9BMQkpioQk7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gOgyR9BMQkpioQk7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gOgyR9BMQkpioQk7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gOgyR9BMQkpioQk7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gOgyR9BMQkpioQk7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gOgyR9BMQkpioQk7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster text{fill:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 .cluster span{color:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gOgyR9BMQkpioQk7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gOgyR9BMQkpioQk7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-gOgyR9BMQkpioQk7 .icon-shape,#mermaid-svg-gOgyR9BMQkpioQk7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gOgyR9BMQkpioQk7 .icon-shape p,#mermaid-svg-gOgyR9BMQkpioQk7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gOgyR9BMQkpioQk7 .icon-shape rect,#mermaid-svg-gOgyR9BMQkpioQk7 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gOgyR9BMQkpioQk7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gOgyR9BMQkpioQk7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gOgyR9BMQkpioQk7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
否
是
否
是
客户端连接
添加认证信息 addAuthInfo
客户端请求操作
服务端获取节点 ACL
遍历 ACL 匹配客户端认证
有匹配项?
拒绝访问 NoAuth
权限足够?
允许操作
9.3 一句话总结
ZooKeeper 的 ACL 机制通过 Scheme + ID + Permissions 的三元组结构,结合可插拔的认证方案和节点级的权限控制,提供了灵活精细的访问控制能力,是保障分布式协调服务数据安全的基石。正确理解和应用 ACL,能够有效防止未授权访问,构建安全可靠的分布式系统。

|
🌺The End🌺点点关注,收藏不迷路🌺 |


