概述
ACL全称为Access Control List(访问控制列表),用于控制资源的访问权限。ZooKeeper使用ACL来控制对其znode(ZooKeeper数据树的数据节点)的访问。ACL实现与UNIX文件访问权限非常相似:它使用权限位来允许/禁止针对节点的各种操作以及位应用的范围。与标准UNIX权限不同,ZooKeeper节点不受用户(文件所有者),组和world(其他)的三个标准范围的限制。
zk利用ACL策略控制节点的访问权限,如节点数据读写、节点创建、节点删除、读取子节点列表、设置节点权限等。
在传统的文件系统中,一个文件拥有某个组的权限即拥有了组里的所有权限,文件或子目录默认会继承自父目录的ACL。而在Zookeeper中,znode的ACL是没有继承关系的,每个znode的权限都是独立控制的,只有客户端满足znode设置的权限要求时,才能完成相应的操作。Zookeeper的ACL,分为三个维度:scheme、id、permission,通常表示为:scheme:id:permission,schema代表授权策略,id代表用户,permission代表权限。下面分别讲述一下这三个属性:
1.scheme
scheme即采取的授权策略,每种授权策略对应不同的权限校验方式。下面是zk常用的几种scheme:
- world:默认方式,相当于全世界都能访问
- auth:不使用任何id,表示任何经过身份验证的用户。
- digest:即用户名:密码这种方式认证,这也是业务系统中最常用的,使用username:password字符串生成MD5哈希,然后将其用作ACL的ID标识。通过以明文形式发送 例如:wangsaichao:123456 来完成身份验证。在ACL中使用时,表达式将是wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=。
- ip:使用Ip地址认证
1.1 world
语法:world:anyone:cdrwa
创建节点默认的scheme,所有人都可以访问。
操作示例:
## 创建新的节点 /node01
[zk: localhost:2181(CONNECTED) 10] create /node01 234
Created /node01
# 查看ACL
[zk: localhost:2181(CONNECTED) 11] getAcl /node01
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 12]
1.2 digest
语法:digest:username:BASE64(SHA1(password)):cdrwa
digest:是授权方式
username:BASE64(SHA1(password)):是id部分
cdrwa:权限部份
用户名+密码授权访问方式,也是常用的一种授权策略。id部份是用户名和密码做sha1加密再做BASE64加密后的组合,比如设置一个节点的用户名为wangsaichao,密码为123456,则表示方式为:
原:wangsaicaho:BASE64(SHA1(123456))
正确:wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=。
密码加密需要用到zk的一个工具类来生成,如下所示:
java -Djava.ext.dirs=/Users/wangsaichao/Desktop/zookeeper-3.4.6/lib -cp /Users/wangsaichao/Desktop/zookeeper-3.4.6/zookeeper-3.4.6.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider wangsaichao:123456
wangsaichao:123456->wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=
操作示例:
## 查看/根节点
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
## 创建节点/node
[zk: localhost:2181(CONNECTED) 2] create /node 123
Created /node
## 设置权限
[zk: localhost:2181(CONNECTED) 3] setAcl /node digest:wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=:cdrwa
cZxid = 0x2
ctime = Sun Sep 09 16:25:51 CST 2018
mZxid = 0x2
mtime = Sun Sep 09 16:25:51 CST 2018
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
## 获取节点刚刚设置的权限
[zk: localhost:2181(CONNECTED) 4] getAcl /node
'digest,'wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=
: cdrwa
## 没有授权,创建子节点失败
[zk: localhost:2181(CONNECTED) 5] create /node/child_01 234
Authentication is not valid : /node/child_01
## 为当前session添加授权信息
[zk: localhost:2181(CONNECTED) 6] addauth digest wangsaichao:123456
## 添加授权信息后,创建子节点成功
[zk: localhost:2181(CONNECTED) 7] create /node/child_01 234
Created /node/child_01
[zk: localhost:2181(CONNECTED) 8]
1.3 auth
scheme为auth时,不需要id。说的不需要id,但是还需要使用一个username:password
的expression来表示这个权限,你也可以理解其实就是id
操作示例:
## 创建一个新的节点 /test_node1
[zk: localhost:2181(CONNECTED) 23] create /test_node1 121
Created /test_node1
## 添加授权账号
[zk: localhost:2181(CONNECTED) 24] addauth digest zookeeper:zookeeper
## 然后设置节点的ACL
[zk: localhost:2181(CONNECTED) 25] setAcl /test_node1 auth:zookeeper:zookeeper:cdrwa
cZxid = 0x13
ctime = Sun Sep 09 17:46:26 CST 2018
mZxid = 0x13
mtime = Sun Sep 09 17:46:26 CST 2018
pZxid = 0x13
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
## 查看刚才设置的ACL
[zk: localhost:2181(CONNECTED) 26] getAcl /test_node1
'digest,'zookeeper:4lvlzsipXVaEhXMd+2qMrLc0at8=
: cdrwa
[zk: localhost:2181(CONNECTED) 27]
这里有一个坑,在使用auth授权时,一定要先执行addauth digest zookeeper:zookeeper然后再授权,否则将使用上一次的授权expression。下面举个例子。执行多次addauth digest 用户名:密码 操作,在新的节点设置auth时,将都会生效。具体例子如下:
## 创建一个新的节点 /test_node2
[zk: localhost:2181(CONNECTED) 27] create /test_node2 234
Created /test_node2
## 设置auth授权, 使用一个并不存在的 hello用户,依然成功了
[zk: localhost:2181(CONNECTED) 28] setAcl /test_node2 auth:hello:hello:cdrwa
cZxid = 0x15
ctime = Sun Sep 09 17:50:10 CST 2018
mZxid = 0x15
mtime = Sun Sep 09 17:50:10 CST 2018
pZxid = 0x15
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
## 查看ACL 竟然是之前的zookeeper用户
[zk: localhost:2181(CONNECTED) 29] getAcl /test_node2
'digest,'zookeeper:4lvlzsipXVaEhXMd+2qMrLc0at8=
: cdrwa
## 这个时候添加 hello 用户
[zk: localhost:2181(CONNECTED) 30] addauth digest hello:hello
## 创建新的节点 /test_node3
[zk: localhost:2181(CONNECTED) 31] create /test_node3 456
Created /test_node3
## 查看ACL 这个时候还是world
[zk: localhost:2181(CONNECTED) 32] getAcl /test_node3
'world,'anyone
: cdrwa
## 设置auth ACL
[zk: localhost:2181(CONNECTED) 33] setAcl /test_node3 auth:hello:hello:cdrwa
cZxid = 0x17
ctime = Sun Sep 09 17:53:14 CST 2018
mZxid = 0x17
mtime = Sun Sep 09 17:53:14 CST 2018
pZxid = 0x17
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
## 查看ACL 发现之前的zookeeper用户也存在
[zk: localhost:2181(CONNECTED) 34] getAcl /test_node3
'digest,'zookeeper:4lvlzsipXVaEhXMd+2qMrLc0at8=
: cdrwa
'digest,'hello:uXpRvPoy9gsHHSCo8uMtZmaXPIA=
: cdrwa
[zk: localhost:2181(CONNECTED) 35]
1.4 ip
基于客户端IP地址校验,限制只允许指定的客户端能操作znode。
比如,设置某个节点只允许IP为127.0.0.1的客户端能读写该写节点的数据:ip:127.0.0.1:rw
操作示例:
## 给node节点添加新的ACL权限
[zk: localhost:2181(CONNECTED) 8] setAcl /node ip:127.0.0.1:cdrwa
cZxid = 0x2
ctime = Sun Sep 09 16:25:51 CST 2018
mZxid = 0x2
mtime = Sun Sep 09 16:25:51 CST 2018
pZxid = 0x5
cversion = 1
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
## 查看ACL
[zk: localhost:2181(CONNECTED) 9] getAcl /node
'ip,'127.0.0.1
: cdrwa
[zk: localhost:2181(CONNECTED) 10]
2.id
id是验证模式,不同的scheme,id的值也不一样。scheme为digest时,id的值为:username:BASE64(SHA1(password)),scheme为ip时,id的值为客户端的ip地址。scheme为world时,id的值为anyone。scheme为auth时,id为 username:password。
3.permission
znode可以拥有的权限还记得之前的授权语句,如:
digest:username:BASE64(SHA1(password)):cdrwa中的cdrwa即是permission。
- CREATE(r):创建子节点的权限
- DELETE(d):删除节点的权限
- READ(r):读取节点数据的权限
- WRITE(w):修改节点数据的权限
- ADMIN(a):设置子节点权限的权限
示例操作:
## 先在当前session中添加 wangsaichao:123456 用户
[zk: localhost:2181(CONNECTED) 35] addauth digest wangsaichao:123456
## 创建一个新的节点,并添加digest ACL(只能创建和删除) 因为是digest 所以密码为加密之后的
[zk: localhost:2181(CONNECTED) 36] create /test_node5 123 digest:wangsaichao:G2RdrM8e0u0f1vNCj/TI99ebRMw=:cd
Created /test_node5
## 没有WRITE权限, 设置节点数据 失败
[zk: localhost:2181(CONNECTED) 37] set /test_node5 234
Authentication is not valid : /test_node5
## 没有ADMIN权限,设置ACL失败
[zk: localhost:2181(CONNECTED) 38] setAcl /test_node5 auth:wangsaichao:123456:cdrwa
Authentication is not valid : /test_node5
## 没有READ权限, 读取节点 失败
[zk: localhost:2181(CONNECTED) 39] get /test_node5
Authentication is not valid : /test_node5
## 具备CREATE权限,创建子节点成功
[[zk: localhost:2181(CONNECTED) 40] create /test_node5/child_01 123
Created /test_node5/child_01
## 具备DELETE权限,可以删除子节点
[zk: localhost:2181(CONNECTED) 41] delete /test_node5/child_01
[zk: localhost:2181(CONNECTED) 42]