文章目录
-
- 1. 概述
-
- 1.1 scheme
- 1.2 授权对象id
- 1.3 permission
- 2. ACL相关命令
- 3. 测试
-
- 3.1 schema=Digest例子
-
- 3.1.1 代码生成ID
- 3.1.2 xshell生成ID
- 3.1.3 总结
- 3.3 schema=Auth 明文授权
- 3.3 schema=IP
- 3.4 schema=world
Access Control在分布式系统中重要性是毋庸置疑的,今天这篇文章来介绍一下Zookeeper中的Access Control(ACL)。
1. 概述
传统的文件系统中,ACL分为两个维度,一个是属组,一个是权限,子目录/文件默认继承父目录的ACL。
Zookeeper 的ACL 权限控制,可以控制节点的读写操作,保证数据的安全性。在Zookeeper中,node的ACL是没有继承关系的,是独立控制的。Zookeeper的ACL,可以从三个维度来理解:一是
scheme
; 二是
user
; 三是
permission
,通常表示为
scheme:id:permissions
。
使用zkCli时,ACL的格式由::三段组成。
- schema:可以取下列值:world, auth, digest, host/ip
- id: 标识身份,值依赖于schema做解析。
- acl:就是权限:cdwra分别表示create, delete,write,read, admin
注意:id受scheme影响,要和其保持一致;permission是独立的;通过冒号来分割三个参数
其特性如下:
- ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限
- 每个znode支持设置多种权限控制方案和多个权限
- 子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点
1.1 scheme
scheme对应于采用哪种方案来进行权限管理,zookeeper实现了一个pluggable的ACL方案,可以通过扩展scheme,来扩展ACL的机制。zookeeper-3.4.4缺省支持下面几种scheme:
-
world
:
它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的
-
: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication)auth
-
digest
:
即用户名:密码这种方式认证,这也是业务系统中最常用的。
用
字符串来产生一个username:password
串,然后该串被用来作为ACL ID。ID表达式为MD5
username:base64
,base64是password的SHA1摘要的编码。
例,假如username=user ,password=123456,那么完整的ACL为:
digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa "digest"对应scheme "user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo"=对应 授权对象id,"6DY5WhzOfGsWQ1XFuIyzxkpwdPo="为username:123456经base64转化的 "cdrwa"对应permissions
-
ip
:
它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
-
super
:
在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
1.2 授权对象id
id与scheme是紧密相关的,具体的情况在上面介绍scheme的过程都已介绍,这里不再赘述。
1.3 permission
zookeeper目前支持下面一些权限:
-
创建权限,可以在在当前node下创建child nodeCREATE(c)
-
删除权限,可以删除当前的nodeDELETE(d)
-
读权限,可以获取当前node的数据,可以list当前node所有的child nodesREAD(r)
-
写权限,可以向当前node写数据WRITE(w)
-
管理权限,可以设置当前node的permissionADMIN(a)
2. ACL相关命令
getAcl:获取某个节点的acl权限信息
setAcl:设置某个节点的acl权限信息
addauth: 输入认证授权信息,相当于注册用户信息,注册时输入明文密码,zk将以密文的形式存
储
节点创建的同时设置ACL:
[zk: localhost:2181(CONNECTED) 13] create /zk-node1 123 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa
Created /zk-node1
或者用setAcl 设置:
[zk: localhost:2181(CONNECTED) 19] setAcl /zk-node1 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa
添加授权信息后,不能直接访问,直接访问将报如下异常:
[zk: localhost:2181(CONNECTED) 16] get /zk-node1
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /zk-node1
访问前需要添加授权信息:
[zk: localhost:2181(CONNECTED) 1 7] addauth digest user:123456
[zk: localhost:2181(CONNECTED) 18] get /zk-node1
123
如果设置权限后,再次致谢setAcl命令,可以覆盖权限,需要重新授权
3. 测试
3.1 schema=Digest例子
格式:
setAcl /test digest:用户名:密码:权限
,密码是用户名和密码加密后的字符串。
3.1.1 代码生成ID
下面代码中有2种形式,输出值不同,一个带user,一个不带user,要特别注意:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
public class ZkTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
// 方式1
String sId = DigestAuthenticationProvider.generateDigest("user:123456");
System.out.println(sId); // user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=
// 方式2
String usernameAndPassword = "user:123456";
byte digest[] = MessageDigest.getInstance("SHA1").digest(usernameAndPassword.getBytes());
Base64 base64 = new Base64();
String encodeToString = base64.encodeToString(digest);
System.out.println(encodeToString); // 6DY5WhzOfGsWQ1XFuIyzxkpwdPo=
}
}
3.1.2 xshell生成ID
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
```例如:
```bash
echo -n root:root | openssl dgst -binary -sha1 | openssl base64
qiTlqPLK7XM2ht3HMn02qRpkKIE=
3.1.3 总结
注意,只有通过
zkCli.sh
设置digest的ACL时id才需要密文,而通过zookeeper的客户端设置digest的ACL时对应的auth数据是
明文
。这个属于编码实现的问题了。
在客户端输入addauth digest user:123456添加授权用户,是明文,如果是脚本,则带密文
和auth比较,digest有如下特性:
- setAcl不需要事先添加认证用户。
- 授权是针对单个特定用户。
- setAcl使用的密码不是明文,是sha1摘要值,无法反推出用户密码内容。
3.3 schema=Auth 明文授权
这种授权不针对任何特定ID,而是对所有已经添加认证的用户,换句话说,就是对所有已经通过认证的用户授权。在当前客户端添加auth授权用户,一旦某个节点被加了auth权限,后续不需要每次在执行命令中增加鉴权参数即可访问节点。
用法如下:
addauth digest <user>:<password>
setAcl <path> auth:<id>:<acl>
注意:
- 必须要先添加认证用户,至少要添加一个认证用户,否则会失败,如下所示:
[zk: localhost:2181(CONNECTED) 0] create /test 'test' [zk: localhost:2181(CONNECTED) 1] setAcl /test auth::crdwa '从未添加过认证用户,会失败' Acl is not valid : /test
- setAcl命令中的id域是被忽略的,可以填任意值,或者空串,例如:
,因为这个域是忽略的,会把所有已经添加的认证用户都加进来setAcl <path> auth::crdwa
这个例子中,我们先添加了三个认证用户tom1,tom2,tom3,然后通过setAcl设置ACL,命令中指定了id为tom2,根据前面的说法,这个id值是被忽略的,写任何值,甚至空值也得到一样的结果。我们看到最后getAcl查询出来的结果包含所有前面添加的三个认证用户。[zk: localhost:2181(CONNECTED) 2] addauth digest tom1:tom1 '//添加认证用户tom1' [zk: localhost:2181(CONNECTED) 3] addauth digest tom2:tom2 '//添加认证用户tom2' [zk: localhost:2181(CONNECTED) 4] addauth digest tom3:tom3 '//添加认证用户tom3' [zk: localhost:2181(CONNECTED) 5] setAcl /test auth:tom2:crdwa '//设置认证用户tom2' [zk: localhost:2181(CONNECTED) 6] getAcl /test 'digest,'tom1:ben+k/3JomjGj4mfd4fYsfM6p0A= : cdrwa 'digest,'tom2:2iJM00A7+qkeKdEXt8Bhgq+IACw= : cdrwa 'digest,'tom3:TAZPWLs6IaYRS8mlvcfyCOwyBJ8= : cdrwa
其实我不是很理解这个功能,难道在一个会话(session)里可以添加多个认证用户 ,那验证的时候按哪一个算呢;如果不同的用户有不同的授权会导致授权冲突吗?以谁为准?
几点总结:- 1.auth的
的,表示给所有认证用户设置acl权限。id值是无效
- 1.1. 认证用户的添加,通过addauth命令(addauth digest :),只在当前会话(session)有效。
- 2.当使用addauth命令添加多个认证用户后,再用auth setAcl来设置acl时,那么所有
都被会加入到acl中。之前addauth的用户
- 3.如果在当前会话中还没有认证过的用户就使用auth setAcl来设置acl权限时会失败,前面已经讨论过。
- 4.在auth setAcl
再使用addauth添加的认证用户是没有acl权限的,之后
auth setAcl来设置权限。必须重新执行
- 5.使用addauth添加的认证用户
,如果此时在另外一个会话中,不添加对应的认证用户,那么就没有相应访问权限的,而且如果再使用auth setAcl来设置acl权限,则会覆盖之前的acl权限信息,而且只会针对当前会话中的认证用户来设置acl权限。只在当前会话(session)有效
- 1.auth的
3.3 schema=IP
IP可以是单个IP地址,也可以是IP地址段,比如ip:192.168.1.0/16
setAcl /node‐ip ip:192.168.100.12:cdwra
create /node‐ip data ip:192.168.100.128:cdwra
3.4 schema=world
这是默认方式,表示没有认证。当创建一个新的节点(znode),而又没有设置任何权限时,就是这个值,例如:
[zk: localhost:2181(CONNECTED) 18] create /noacl '//创建一个节点,没有值,也没有设定权限'
Created /noacl
[zk: localhost:2181(CONNECTED) 19] getAcl /noacl '//查看权限'
'world,'anyone '//显示权限为world'
: cdrwa
看到/noacl的ACL属于就是world schema的,因为它没有设置ACL属性,这样任何人都可以访问这个节点。
如果要手工设置这个属性,那么此时的id域只允许一个值,即anyone,格式如下:
setAcl /newznode world:anyone:crdwa
参考:
《说说Zookeeper中的ACL》
《zookeeper的ACL权限控制》
《对zookeeper设置ACL属性》 写的比较好,深入浅出