本章定位:ACL(Access Control List)是 ZooKeeper 保障 ZNode 数据安全的核心机制。掌握 ACL 才能在分布式环境中安全地共享协调数据。
定义与作用
ACL 控制谁可以对 ZNode 执行什么操作。每个 ZNode 都有自己的 ACL 列表,由一组 (scheme:expression, permissions) 对组成。
ACL 解决的核心痛点:
- 多租户共享 ZooKeeper 集群时的数据隔离
- 生产环境误操作防护(如测试客户端误删生产配置)
- 敏感配置数据(数据库密码、API Key)的访问控制
核心原理
五种权限
| 权限 | 字母 | 含义 | 影响的操作 |
|---|---|---|---|
| CREATE | c | 可创建子节点 | create() |
| READ | r | 可读取数据和子节点列表 | getData(), getChildren(), exists() |
| WRITE | w | 可修改节点数据 | setData() |
| DELETE | d | 可删除子节点 | delete() |
| ADMIN | a | 可修改 ACL | setACL() |
四种内置 Scheme
world 是默认方案(
world:anyone),任何人拥有全部权限。digest 是最常用的认证方案,通过用户名密码认证。ip 适合内网白名单场景。
ACL 不递归
ACL 仅作用于当前 ZNode,不继承到子节点。父节点 ACL 与子节点 ACL 完全独立。
/app ACL: world:anyone:cdrwa(所有人)
/app/config ACL: digest:admin:xxxxx:cdrwa(仅 admin 可用)
/app/public ACL: world:anyone:r(所有人只读)
完整示例
示例一:digest 认证的完整流程
场景说明:对 /app/config 节点设置 digest 认证,仅 admin 用户可读写。
操作前状态:节点 /app/config 使用默认 ACL(world:anyone:cdrwa)。
zkCli.sh -server 127.0.0.1:2181
# 1. 查看当前 ACL
[zkshell: 0] getAcl /app/config
'world,'anyone
: cdrwa
# 2. 添加认证身份
[zkshell: 1] addauth digest admin:admin123
# 3. 设置 ACL —— 仅 admin 拥有全部权限
[zkshell: 2] setAcl /app/config auth:admin:cdrwa
# 4. 验证 —— 当前会话 (admin) 可读
[zkshell: 3] get /app/config
port=8080
# 5. 验证 —— 新会话(未认证)被拒绝
# 在另一个终端:
zkCli.sh -server 127.0.0.1:2181
[zkshell: 0] get /app/config
Authentication is not valid : /app/config
Java API 实现:
ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 3000, event -> {});
// 认证
zk.addAuthInfo("digest", "admin:admin123".getBytes());
// 创建 ACL
ACL acl = new ACL(ZooDefs.Perms.ALL,
new Id("auth", "admin"));
List<ACL> acls = Collections.singletonList(acl);
// 设置 ACL
zk.setACL("/app/config", acls, -1);
操作后状态:
| 会话 | 认证身份 | 操作 /app/config | 结果 |
|---|---|---|---|
| 当前会话 | admin | get / setData | 成功 |
| 新会话 | 无 | get | NoAuthException |
示例二:IP 白名单场景
场景说明:生产配置节点仅允许内网指定 IP 的服务器读取。
# 设置 ACL —— 仅 192.168.1.0/24 网段可读
[zkshell: 0] setAcl /app/config ip:192.168.1.0/24:r
# 192.168.1.10 机器上的客户端
[zkshell: 0] get /app/config
port=8080
# 外网 10.0.0.1 机器上的客户端
[zkshell: 0] get /app/config
Authentication is not valid : /app/config
操作前后对比:
| 来源 IP | ACL 设置前 | ACL 设置后 |
|---|---|---|
| 192.168.1.x(内网) | 可读写 | 可读(不可写) |
| 10.0.0.x(外网) | 可读写 | 无权限 |
示例三:多权限混合 ACL
场景说明:一个节点允许 admin 用户全权限,其他用户只读。
[zkshell: 0] create /app/mixed "mixed-data"
Created /app/mixed
# 添加认证
[zkshell: 1] addauth digest admin:admin123
# 设置混合 ACL
[zkshell: 2] setAcl /app/mixed \
auth:admin:cdrwa,\
world:anyone:r
[zkshell: 3] getAcl /app/mixed
'digest,'admin:QIbUSW6wR4RcBU...
: cdrwa
'world,'anyone
: r
操作前后对比:
| 角色 | 读 | 写 | 创建子节点 | 删除 | 修改 ACL |
|---|---|---|---|---|---|
| admin(已认证) | ✅ | ✅ | ✅ | ✅ | ✅ |
| 匿名用户 | ✅ | ❌ | ❌ | ❌ | ❌ |
易错场景与面试考点
易错场景
1. 忘记 addauth 就设置 auth ACL
# 没有先 addauth
[zkshell: 0] setAcl /node auth:user:cdrwa
# Acl is not valid : /node
# 原因:auth scheme 需要当前会话已有认证身份
必须先执行 addauth,才能用 auth scheme 设置 ACL。
2. 设置 ACL 后把自己锁在外面
# 设置 digest ACL 但未先 addauth
[zkshell: 0] setAcl /node digest:admin:hashedPwd:cdrwa
[zkshell: 1] get /node
# Authentication is not valid
# 自己也无法读取!
正确流程:先 addauth 建立身份 → 再 setAcl。
3. ACL 不递归带来的安全隐患
# /app 是所有人可读
# /app/secrets 可能被疏忽设置为继承父节点
create /app/secrets "password=secret"
# 默认 ACL 是 world:anyone:cdrwa !任何人可读写
每次创建节点都应显式考虑 ACL。可使用 Curator 的 withACL() 统一管理。
面试高频题
Q:ZooKeeper ACL 与 Unix 文件权限有何不同?
A:
- ZooKeeper 不区分 owner/group/other,而是使用
scheme:expression的身份模型 - ZooKeeper 有 ADMIN 权限(修改 ACL)和 CREATE/DELETE 的细粒度拆分
- ZooKeeper ACL 不递归,Unix 默认也不递归但可通过 setfacl -R 实现
- ZooKeeper 无 LOOKUP 权限(可遍历目录但不可列出),因为不需要
Q:auth 和 digest scheme 的区别?
A:
digest:ACL 中存储的是username:base64(sha1(password))的静态哈希值,任何知道密码的用户都可以匹配auth:不存储具体身份信息,而是动态引用当前会话的认证身份。设置后,只有该会话创建者可以访问
Q:如何实现"节点创建者才有全部权限"?
A:使用 auth scheme 配合 ZOO_CREATOR_ALL_ACL:
zk.addAuthInfo("digest", "user:password".getBytes());
zk.create("/node", data,
ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
这样 /node 的 ACL 为 auth::cdrwa,只有该用户能操作。
小结
| 要点 | 说明 |
|---|---|
| 5 种权限 | CREATE、READ、WRITE、DELETE、ADMIN |
| 4+1 种 Scheme | world、auth、digest、ip、x509 |
| ACL 不递归 | 子节点需独立设置 |
| 默认 ACL | world:anyone:cdrwa(全员全权限) |
| auth vs digest | auth 动态、digest 静态哈希 |
| IP 白名单 | 通过 ip scheme + 子网掩码实现 |
ACL 是安全的第一道防线。下一节将深入顺序节点的机制,理解它在分布式锁和队列中的核心作用。