组件

ZooKeeper ACL介绍

ZooKeeper ACL介绍
zookeeper
Answer
12/23/16 5:25 AM
A. 资源与参考文档
 
关联项目:DCC

B. 官方文档摘要

ZooKeeper使用ACLs来控制到它的znodes的存取权限。ACL实现与UNIX文件存取权限非常相似:它用权限位(permission bits)确定各种操作对某个节点是否是允许的。ACL指定id集以及这些id集拥有的权限。
 
注意ACL只针对当前节点,并不会影响子孙节点。(非递归)
 
ZooKeeper支持可插拔的认证模式(authentication schemes)。Ids由 scheme:id 指定,scheme指明id属于哪一种认证模式。例如,ip:172.16.16.1 是一个主机id,其IP地址为 172.16.16.1
 
ACLs由多组 (scheme:expression, perms) 组成。其中的表达式的格式是由模式决定的。例如,(ip:19.22.0.0/16, READ) 给予所有IP地址为19.22.xxx.xxx 的机器读权限。
 
当一个客户端连接到ZooKeeper并认证自己时, ZooKeeper会把这个客户端相关的id与这次连接关联上。每当客户端试图访问节点时,ZooKeeper都会检查这些id是否在该节点的ACL列表中。
 
ACL 权限
ZooKeeper支持以下权限: 
  • CREATE: you can create a child node
  • READ: you can get data from a node and list its children.
  • WRITE: you can set data for a node
  • DELETE: you can delete a child node
  • ADMIN: you can set permissions
 
内建的ACL模式
  • world 只有一种id anyone,表示所有人。
  • auth 不用任何id,代表任意认证用户。
  • digest 使用 username:password 生成的消息摘要作为ACL id。通过发送明文 username:password 获取认证。而ACL表达式是 username:id 的形式,其中 id 就是整个 username:password 使用SHA1 摘要后再用 BASE64 编码的值。(与文档不一致,经过测试与阅读源码,确定至少在3.4.9版本下,以本段描述为准)
  • ip 使用客户端主机IP作为ACL id。ACL表达式格式为 addr/bits,例如19.22.0.0/16。
  • x509 
 
可插拔式认证
简而言之,就是开发自定义的scheme。放到以后在研究。目前只要知道ZooKeeper支持自己扩展认证模式就可以了。

C. 试验

官方文档中找不到 zkCli setAcl 的详细说明,只能自己试了。
 
目标1:尝试使用IP过滤,使得DCC客户端只能读取配置而不能写入配置
  1. getAcl /dcc,发现默认Acl为      'world,'anyone   : cdrwa
  2. setAcl /dcc ip:10.203.25.121:rwcda,设置只有10.203.25.121才能操作该节点
  3. 此时,ssh到121机器使用zkCli.sh是可以操作该节点的;但是在别的机器上是无法访问该节点的
 
遗留问题:不知道如何同时设置多个IP白名单。不知道如何使用 addr/bits 格式设置一个范围的IP。不知道怎样让白名单IP有所有权限,而其它IP只有读权限。
 
注意:如果用 ./zkCli.sh -server 127.0.0.1:4180 连接服务器,则无法通过ACL验证!
 
目标2:清除ACL
setAcl /dcc world:anyone:rwcda
 
目标3:尝试只有认证用户才能写
 
方向错误!任意客户端都能生成任意认证用户(即auth),因为 addauth digest username:password 总是合法的,只不过这个(在该session合法的)auth 不一定能通过 server 上节点的 ACL 检查。
所以不像常见的系统,我们在客户端输入的用户名密码并不会直接先去服务端验证,所以整个思路是死路。
 
目标4:尝试只有指定用户才能写
  1. addauth digest dcc:Pass1234,增加dcc用户,其密码为Pass1234
  2. setAcl /dcc auth:dcc:Pass1234:rwcda,为 /dcc 节点指定只有 dcc 这个用户才能操作
  3. getAcl /dcc,可以看到ACL设置成功,为:'digest,'dcc:4GnHub8nhgw//yFRkJUfAn3GNjg=   : cdrwa
 
遗留问题:同样不知道如何做到多用户权限细分。
 
个人理解:显然,ZooKeeper服务端并没有独立的用户模块,所谓的用户信息全在ACL里面。
 

D. 代码试验

命令行不行,那就上代码。
 
1. 快速获取 digest 值代码
        try {
            // 快速获得 username:password 对应的 digest 值
            System.out.println(DigestAuthenticationProvider.generateDigest("super:Pass1234"));
            // 验证 digest 到底是对哪一段进行的
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update("super:Pass1234".getBytes());
            byte messageDigest[] = digest.digest();
            System.out.println(new sun.misc.BASE64Encoder().encode(messageDigest));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
 
2. 按照用户细分权限
            ZooKeeper zk = new ZooKeeper("10.203.25.121:4180,10.203.25.122:4180,10.203.25.123:4180", 300000, null);
            List<ACL> list = new ArrayList<ACL>();
            Id idAdmin = new Id("digest", DigestAuthenticationProvider.generateDigest("dcc:Pass1234"))
            ACL aclAdmin = new ACL(ZooDefs.Perms.ALL, idAdmin);
            list.add(aclAdmin);
            Id idCommon = new Id("digest", DigestAuthenticationProvider.generateDigest("common:Pass1234")); 
            ACL aclCommonn = new ACL(ZooDefs.Perms.READ, idCommon);
            list.add(aclCommonn);
            zk.setACL("/test", list, -1);
如此这般,/test节点的ACL即变为:
'digest,'dcc:4GnHub8nhgw//yFRkJUfAn3GNjg=
: cdrwa
'digest,'common:vczgdSZVoTO4JxhELO02KPjQWB0=
: r
试验发现,common账号只能读取数据,dcc账号拥有全部权限。其它账号什么也做不了。
 
对应的客户端提供认证信息的代码为:
            ZooKeeper zk = new ZooKeeper("10.203.25.121:4180,10.203.25.122:4180,10.203.25.123:4180", 300000, null);
            zk.addAuthInfo("digest", "common:Pass1234".getBytes());
            System.out.println(new String(zk.getData("/test", false, null)));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0 (0 Votes)