4.5 ACL 权限控制:案卷的访问登记簿


文档摘要

4.5 ACL 权限控制:案卷的访问登记簿 本节摘要:每个 ZNode 都挂着一张访问控制表:谁(scheme 加 id)能对它做什么(权限位)。本节讲清五种认证方式、七类权限位、父节点权限对子节点的实际影响,以及共享集群上最常用的 digest 配方与常见翻车现场。 一张容易漏办的保险 多应用共享一个 ZooKeeper 集群是常态,但默认配置下任何人都能读写任何节点——只要能连上 2181 端口。真实事故的形状通常是:两个团队共用集群,一个应用的清理脚本把路径写宽了半个字符,删光了另一个应用的配置树。ACL(Access Control List)就是防这口的锁:它在节点级声明访问资格,谁能在哪个卷宗上做什么,登记在案。 先立三个认知坐标。

4.5 ACL 权限控制:案卷的访问登记簿

本节摘要:每个 ZNode 都挂着一张访问控制表:谁(scheme 加 id)能对它做什么(权限位)。本节讲清五种认证方式、七类权限位、父节点权限对子节点的实际影响,以及共享集群上最常用的 digest 配方与常见翻车现场。

一张容易漏办的保险

多应用共享一个 ZooKeeper 集群是常态,但默认配置下任何人都能读写任何节点——只要能连上 2181 端口。真实事故的形状通常是:两个团队共用集群,一个应用的清理脚本把路径写宽了半个字符,删光了另一个应用的配置树。ACL(Access Control List)就是防这口的锁:它在节点级声明访问资格,谁能在哪个卷宗上做什么,登记在案。

先立三个认知坐标。其一,ACL 不提供用户体系,它只是"认证方式加资格表"的组合,认证靠 scheme 在建连或操作时完成。其二,ACL 不从父节点继承——/a 设了只读,/a/b 依然按自己表执行;只是创建子节点需要父节点的创建权限,读写时各看各表。其三,权限校验发生在受理服务器本地,属轻量操作,不会成为性能瓶颈。

scheme 与权限位:两张小表背下来

**认证方式(scheme)**五种常用:world(所有人,唯一 id 是 anyone)、digest(用户名密码,用 SHA1 加密摘要存储)、auth(已登录的当前用户)、ip(来源地址段)、super(超级管理员,越过一切校验)。权限位七类:CREATE、DELETE、READ、WRITE、ADMIN(能改 ACL 本身)五大件,外加 ALL(全权)与 READ 以外都算的写族。日常组合记住一个口诀:读共享用 READ 广开,写收紧到 digest。

实操:给配置树上一把 digest 锁

zkCli 的 addauth 与 setAcl 组合是日常主力。目标效果:/app-a 子树只有 user-a 能写,任何人可读:

$ zkCli.sh -server 127.0.0.1:2181 # 1. 先在会话里声明身份(后续该会话的写操作都以此身份认证) [zk] addauth digest user-a:pass-a # 2. 创建节点并直接指定 ACL:只有 user-a 可读写,world 众人只读 [zk] create /app-a "secret" [zk] setAcl /app-a digest:user-a:加密串:cdwra, world:anyone:r [zk] getAcl /app-a 'digest,'user-a : cdrwa 'world,'anyone : r # 3. 未认证会话的体验:读得到、写不进 $ zkCli.sh -server 127.0.0.1:2181 [zk] get /app-a secret # READ 对 world 开放 [zk] set /app-a "hacked" Authentication is not valid : /app-a # 拒绝

编程侧同理,Curator 在 builder 与每次操作上都能挂 ACLProvider。注意密码传的是明文,框架与命令行都会算成摘要存储:

// Curator 侧:会话级身份声明 + 创建时挂 ACL client = CuratorFrameworkFactory.builder() .connectString("127.0.0.1:2181") .authorization("digest", "user-a:pass-a".getBytes()) // 等价 addauth .retryPolicy(new ExponentialBackoffRetry(1000, 3)) .build(); client.start(); // 创建时直接带 ACL:digest 身份全权,匿名只读 List<ACL> acls = new ArrayList<>(); acls.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", DigestAuthenticationProvider.generateDigest("user-a:pass-a")))); acls.add(new ACL(ZooDefs.Perms.READ, ZooDefs.Ids.ANYONE_ID_UNSAFE)); client.create().creatingParentsIfNeeded() .withACL(acls) .forPath("/app-a/config/db", "jdbc:demo".getBytes());

ip 方式适合内网机器对机器的信任:setAcl /ops ip:10.0.0.0/24:cdra 把运维子树限制在网段内。但别对它有过高期待——地址可伪造,它防误操作有余、防恶意不足。

三种翻车现场与自救

现场一:锁死在自己门外。/app-a 只留了 digest 身份,会话重启忘了 addauth,读全报 NoAuth。自救路径:用超级管理员身份连入(服务端启动参数里配置 super scheme 的账号密码),或该节点无子节点时由有权限的会话重建。预防:改动 ACL 前先用当前会话跑一遍关键读写。

现场二:以为权限会继承。 只给 /app-a 设了 ACL,之后创建的 /app-a/config 用的是创建会话的默认表(world 全开)。ACLEveryone 看似设防实则漏风。预防:把 ACLProvider 挂在客户端 builder 上,让所有创建动作自动带表。

现场三:删不掉、读不了的"幽灵节点"。 前一个应用的会话用某 digest 建了节点后下线,新会话既无身份又无 ADMIN 权限,连 getAcl 都看不到。自救:super 账号接管;预防:共享集群的节点命名规范里加一条——每个应用只在自己 namespace 子树内活动(3.3 节的 namespace 参数正是为此)。

# 验证 ghost 节点:无权限会话的视角 [zk] getAcl /ghost-node Authentication is not valid : /ghost-node # 连表都看不到,因为没有 READ 与 ADMIN # super 账号连入后接管: # 服务端环境变量 -Dzookeeper.DigestAuthenticationProvider.superDigest=super:加密串 [zk] addauth digest super:super-pass [zk] setAcl /ghost-node world:anyone:cdrwa # 夺回控制权,按需重设

要点回顾

  • 节点级授权、不继承:读写各看本节点 ACL,但创建子节点要过父节点 CREATE 权限,理解偏差是多数翻车根源。
  • digest 是共享集群默认解:addauth 声明身份加 setAcl 挂表,读写分离用"digest 全权加 world 只读"组合。
  • ip 防误不防恶:内网信任可用,安全要求高的场景叠加 digest 或外置认证。
  • 先想好退路:super 账号要提前配置演练,namespace 隔离让每个应用只动自己的子树。

常见疑问

问:有没有节点的全局管理后台能看全部 ACL? 没有现成的。ACL 按"有无资格"隐藏信息,无 READ 权限的会话连节点存在与否都不可见。运维盘点要靠 super 账号遍历,或定期用脚本以各应用身份自检。

第四章五个案件全部审结。下一章带着这些机制去现场:四个经典判例逐一开庭。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U