Zookeeper 权限操作ACL
在生产环境中, zk 集群通常是部署在一组单独的服务器组上, 多个应用共同使用一个zk 集群, 以节省服务器资源. 当多个应用共同使用一个zk 集群时, 就需要对不同应用进行权限隔离了, zk 提供了简单的ACL 进行权限控制.
1. ACL 简介
- 传统的文件系统中, 子目录/文件默认继承父母录的ACL 权限, 但是zk 中, zNode 的ACL 权限是没有任何继承关系的, 都是独立控制的, 也就是说zk 的ACL 是针对ZNode 节点的.
1. zNOde 权限
- zk 中zNode 有五种权限 cdrwa, 用于控制当前节点的数据,ACL 权限修改和创建/删除子节点
- znode 中当前节点的权限不能限制对本节点的删除, 此权限由父节点控制
权限标识 | 含义 | 描述 |
---|---|---|
a | Admin | 允许修改本节点的ACL 权限 |
r | Read | 允许获取本节点的数据和子节点列表 |
w | Write | 拥有Read权限, 可修改本节点数据 |
c | Create | 允许创建子节点 |
d | Delete | 允许删除子节点 |
2. ACL 内置认证方式
zk 内置了四种ACL Schemes, 即四种认证方式, 可自行扩展, 通常使用auth 和 digest 权限控制就够了, 因为通常zk 集群都是部署在内网中, 供内网机器访问的.
认证方式 | 说明 | 示例 |
---|---|---|
world | 默认ACL, 只有一个唯一的id anyone, 代表所有人 | setACL /a world:anyone:cr |
auth | 不适用任何id, 代表任何已认证的用户 | addAuth digest usr:pwd; setACL /a auth::cr |
digest | 指定用户名密码认证 | setACL /a digest:usr:bash64(SHA1(pwd)):cr |
ip | 客户端主机IP认证, 是客户端的主机IP做为ACL ID | setACL /a ip:192.145.1.100/0:cr |
zk 命令行中 auth 和 digest 区别:
- auth方式, 对于一个ZNode可以同时设置多个用户访问权限, 只不过这些用户的权限是相同的: 使用addAuth 认证多个用户即可
- digest方式, 设置权限时, 一个节点只能设置一个用户访问
- digest 方式设置时, 密码需要使用密文, 否则不能访问, 具体密文获取方式可通过zookeeper 中自带工具实现
3. zk 权限相关的命令
zk ACL 相关的命令有:
命令 | 命令格式 | 含义 |
---|---|---|
addAuth | addAuth digest usr:pwd | 为当前登录用户添加用户认证信息 |
create | create path value acl | 创建zNOde时同时指定ACL 权限 |
setAcl | setAcl pathh acl | 设置zNode的ACL 权限 |
getAcl | getAcl pathh | 获取zNode 的ACL 权限 |
2. 认证测试
2.1 world 认证
- world 认证是zk 默认的认证方式, 代表所有人,默认权限为cdrwa
- 创建zNode时, 如果不指定ACL 权限, 节点的默认权限为word:anyone:cdrwa, 即所有人拥有全部权限, 但是使用setAcl 命令时, 没有默认ACL权限, 必须制定ACL 信息
[zk: 127.0.0.1:2181(CONNECTED) 5] create /world world world:anyone:cd
Created /world
[zk: 127.0.0.1:2181(CONNECTED) 6] create /wd world
Created /wd
[zk: 127.0.0.1:2181(CONNECTED) 7] getAcl /world
'world,'anyone
: cd
[zk: 127.0.0.1:2181(CONNECTED) 8] getAcl /wd
'world,'anyone
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 9] setAcl /wd world:anyone:cda
cZxid = 0x1c00000003
ctime = Sun Jul 30 09:07:52 CST 2017
mZxid = 0x1c00000003
mtime = Sun Jul 30 09:07:52 CST 2017
pZxid = 0x1c00000003
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: 127.0.0.1:2181(CONNECTED) 10] getAcl /wd
'world,'anyone
: cda
2.2 auth 认证
- 为节点设置auth 认证模式时, 需实现使用addauth 添加认证信息, 可通过addauth添加多组认证信息, 这样两个用户对此节点拥有相同的权限
- addauth 通过用户名和密码添加认证信息, 用户密码会被采用base64(sha1(pwd))加密;
[zk: 127.0.0.1:2181(CONNECTED) 0] addauth digest mirror:mirror
[zk: 127.0.0.1:2181(CONNECTED) 1] addauth digest zong:zong
[zk: 127.0.0.1:2181(CONNECTED) 2] create /test/auth test_auth auth::cda
Created /test/auth
[zk: 127.0.0.1:2181(CONNECTED) 3] getAcl /test/auth
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cda
'digest,'zong:rJQhMsjxDyaqJWO4eOO1lOGKNxc=
: cda
[zk: 127.0.0.1:2181(CONNECTED) 4] get /test/auth
Authentication is not valid : /test/auth
[zk: 127.0.0.1:2181(CONNECTED) 7] setAcl /test/auth auth::cdrwa
cZxid = 0x1c00000008
ctime = Sun Jul 30 09:15:29 CST 2017
mZxid = 0x1c00000008
mtime = Sun Jul 30 09:15:29 CST 2017
pZxid = 0x1c00000008
cversion = 0
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: 127.0.0.1:2181(CONNECTED) 8] getAcl /test/auth
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cdrwa
'digest,'zong:rJQhMsjxDyaqJWO4eOO1lOGKNxc=
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 9] get /test/auth
test_auth
cZxid = 0x1c00000008
ctime = Sun Jul 30 09:15:29 CST 2017
mZxid = 0x1c00000008
mtime = Sun Jul 30 09:15:29 CST 2017
pZxid = 0x1c00000008
cversion = 0
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
2.3 digest 认证
- digest 认证和auth 认证非常相似, 只不过digest 认证无须实现通过addauth 添加认证用户信息, 而是直接用户名和密码设置权限, 只不过密码不是明文, 而是密文
- digest 密文加密方式为base64(sha1(pwd)), 可以通过zk api生成, 或者在客户端使用addauth命令生成认证信息, 然后赋予一个测试节点, 然后再查看acl 信息, 这样就能看到用户名密码加密后的密文了.
[zk: 127.0.0.1:2181(CONNECTED) 0] create /test/123 1234 digest:mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=:cdrwa
Created /test/123
[zk: 127.0.0.1:2181(CONNECTED) 1] getAcl /test/123
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 2] get /test/123
Authentication is not valid : /test/123
[zk: 127.0.0.1:2181(CONNECTED) 3] addauth digest mirror:mirror
[zk: 127.0.0.1:2181(CONNECTED) 4] get /test/123
1234
cZxid = 0x1c0000000d
ctime = Sun Jul 30 09:22:45 CST 2017
mZxid = 0x1c0000000d
mtime = Sun Jul 30 09:22:45 CST 2017
pZxid = 0x1c0000000d
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
2.4 ip 认证
- zk ACL 支持IP 认证方式, 但这种方式笔者并不常用, 就不做过多介绍了
4. 默认根节点权限
1. 查看根节点ACL 权限
- 根节点默认权限为 world:anyone:cdrwa, 此权限表示任何人都能删除根节点下的所有空节点(不含子节点的权限), 因此可选择修改根目录的权限, 因此这种方式并不是太安全.
[zk: 127.0.0.1:2181(CONNECTED) 0] getAcl /
'world,'anyone
: cdrwa
2. 测试根节点默认权限
- 查看根节点权限, 创建数据
[zk: 127.0.0.1:2181(CONNECTED) 0] getAcl /
'world,'anyone
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 1] addauth digest mirror:mirror
[zk: 127.0.0.1:2181(CONNECTED) 2] create /a a auth::cdrwa
Created /a
[zk: 127.0.0.1:2181(CONNECTED) 3] create /a/aa a_aa auth::cdrwa
Created /a/aa
[zk: 127.0.0.1:2181(CONNECTED) 4] create /b b auth::cdrwa
Created /b
- 退出重新登录, 不认证用户信息, 默认为anyone; 由于a 节点存在子节点所以删除失败, 但是b 节点不存在子节点, 可以成功删除, 虽然b 拥有ACL 权限
[zk: 127.0.0.1:2181(CONNECTED) 0] getAcl /a
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 1] getAcl /a/aa
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 2] getAcl /b
'digest,'mirror:R1vnwJN21HmcYWH2CB7NwyIxB14=
: cdrwa
[zk: 127.0.0.1:2181(CONNECTED) 3] delete /b
[zk: 127.0.0.1:2181(CONNECTED) 4] rmr /a
Authentication is not valid : /a
3. 修改根节点权限
- 可以创建一管理用户, 对根节点拥有全部权限. 然后由管理员为每一个应用创建一个一级节点, 且此用户对该一级节点拥有所有权限
[zk: 127.0.0.1:2181(CONNECTED) 0] addauth digest admin:admin
[zk: 127.0.0.1:2181(CONNECTED) 1] setAcl / auth::cdrwa
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x1b00000030
cversion = 20
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
[zk: 127.0.0.1:2181(CONNECTED) 2] getAcl /
'digest,'admin:x1nq8J5GOJVPY6zgzhtTtA9izLc=
: cdrwa