2021SC@SDUSC
ACL基本概念ZooKeeper 的权限管理亦即ACL控制功能,使用ACL来对Znode进行访问控制。ACL的实现和Unix文件访问许可非常相似:它使用许可位来对一个节点的不同操作进行允许或禁止的权限控制。但是和标准的Unix许可不同的是,Zookeeper对于用户类别的区分,不止局限于所有者(owner)、组 (group)、所有人(world)三个级别。Zookeeper中,数据节点没有"所有者"的概念。访问者利用id标识自己的身份,并获得与之相应的不同的访问权限。
深入ACL源码我们首先来看看ACL类
public class ACL implements Record {
private int perms;
private org.apache.zookeeper.data.Id id;
如上,该类实现了Record接口(在zookeeper中实现该接口,表明类是生成的)
ACL类有两个变量,分别代表了权限值(perms)和ACL的验证实体(id)。
紧接着,我们来考察ID类,该类代表不同ACL模式下的具体实体。
public class Id implements Record {
private String scheme;
private String id;
如上,同样地,该类实现了Record接口
Record类有两个变量,scheme指验证模式,而id则代表在scheme的验证模式下的具体内容。
perms@InterfaceAudience.Public
public interface Perms {
int READ = 1 << 0;
int WRITE = 1 << 1;
int CREATE = 1 << 2;
int DELETE = 1 << 3;
int ADMIN = 1 << 4;
int ALL = READ | WRITE | CREATE | DELETE | ADMIN;
}
zookeeper中的权限设置与Unix的文件权限(可读,可写,可执行)很类似,对某种权限的表示也仅仅用一个bit,如上所示,int的最后五个bit依次表示(Admin,Delete,Create,Write,Read)
具体地,这五种权限是指:
① Read 允许对本节点GetChildren 和GetData 操作
② Write 允许对本节点SetData 操作
③ Create 允许对子节点Create 操作
④ Delete 允许对子节点Delete 操作
⑤ Admin 允许对本节点setAcl 操作
PS:关于权限设置,有两点要注意
- zk的权限系统中没有所谓user,group,others的概念,也就是说没有一个用户或者说用户组是一个znode的拥有者,但是可以给一群用户或一个用户赋予某个znode admin的权限。
- 对某个znode设置的ACL只对它自己有效,对它的子节点无效的
PPS:perms我想应该是permissions的缩写
schemezookeeper默认提供了五种scheme(zookeeper也允许你扩展scheme),这五种权限管理方案如下
①world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的
②auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication)
③digest: 它对应的id为username:base64(SHA1(password)),它需要先通过username:password形式的authentication
④ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
⑤super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa---也就是上述五种权限)
@InterfaceAudience.Public
public interface Ids {
//默认的为world模式设置的ID
Id ANYONE_ID_UNSAFE = new Id("world", "anyone");
//默认的为auth模式设置的ID,代表了任何已经被确认的用户,在setacl的时候使用
Id AUTH_IDS = new Id("auth", "");
//默认的open ACL LIst,表示所有用户(ANYONE_ID_UNSAFE)有所有权限
@SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION", justification = "Cannot break API")
ArrayList OPEN_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));
//默认的creator ACL LIst,表示auth_ids这些账号有所有权限
@SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION", justification = "Cannot break API")
ArrayList CREATOR_ALL_ACL = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));
//默认的read ACL LIst,表示所有账号(ANYONE_ID_UNSAFE)有read权限
@SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION", justification = "Cannot break API")
ArrayList READ_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));
}
如上,我们可以看到zookeeper提供了两种默认的ID实例,分别是world和auth两种scheme的实现
public KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte[] authData) {
//把验证信息转换为string
String id = new String(authData);
try {
//加密
String digest = generateDigest(id);
//判断是否是super
if (digest.equals(superDigest)) {
//加入一个super的Id
cnxn.addAuthInfo(new Id("super", ""));
}
//加入digest schema下的id为digest变量值的ID
cnxn.addAuthInfo(new Id(getScheme(), digest));
return KeeperException.Code.OK;
} catch (NoSuchAlgorithmException e) {
LOG.error("Missing algorithm", e);
}
return KeeperException.Code.AUTHFAILED;
}
如上,在 DigestAuthenticationProvider类的handleAuthentication方法中实现了super scheme和digest scheme
注:superDigest的值可以在运行前配置环境变量来控制
public String getScheme() {
return "ip";
}
public KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte[] authData) {
String id = cnxn.getRemoteSocketAddress().getAddress().getHostAddress();
cnxn.addAuthInfo(new Id(getScheme(), id));
return KeeperException.Code.OK;
}
如上,在IPAuthenticationProvider类的handleAuthentication方法中实现了ip scheme



