生产环境中,经常会有多个项目使用zookeeper,例如多个hbase集群。每个项目搭建一套独立的zookeeper,无论从机器成本,还是运维成本,都是一笔额外的开销。
然而多项目,多集群共用zookeeper又涉及一个权限隔离的问题。zookeeper本身提供了ACL机制,表示为scheme:id:permissions,第一个字段表示采用哪一种机制,第二个id表示
用户,permissions表示相关权限( CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,这5种权限简写为crwda)。
zookeeper提供了如下几种机制(scheme):
- world: 它下面只有一个id, 叫anyone, 代表任何人
- auth: 它不需要id, 只要是通过认证的user都有权限(zookeeper支持通过kerberos来进行认证 , 也支持username/password形式的认证)
- digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的认证
- ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
- super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
下面演示一个通过digest(用户名密码的方式)为创建的节点设置ACL的例子:
import org.apache.zookeeper.*;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.apache.zookeeper.data.*;
import java.util.*;
public class NewDigest {
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.apache.zookeeper.data.*;
import java.util.*;
public class NewDigest {
public static void main(String[] args) throws Exception {
// new一个acl
List<ACL> acls = new ArrayList<ACL>();
// 添加第一个id,采用用户名密码形式
Id id1 = new Id("digest",
DigestAuthenticationProvider.generateDigest("admin:admin"));
ACL acl1 = new ACL(ZooDefs.Perms.ALL, id1);
acls.add(acl1);
// 添加第二个id,所有用户可读权限
Id id2 = new Id("world", "anyone");
ACL acl2 = new ACL(ZooDefs.Perms.READ, id2);
acls.add(acl2);
// zk用admin认证,创建/test ZNode。
ZooKeeper zk = new ZooKeeper(
"host1:2181,host2:2181,host3:2181",
2000, null);
zk.addAuthInfo("digest", "admin:admin".getBytes());
zk.create("/test", "data".getBytes(), acls, CreateMode.PERSISTENT);
}
}
List<ACL> acls = new ArrayList<ACL>();
// 添加第一个id,采用用户名密码形式
Id id1 = new Id("digest",
DigestAuthenticationProvider.generateDigest("admin:admin"));
ACL acl1 = new ACL(ZooDefs.Perms.ALL, id1);
acls.add(acl1);
// 添加第二个id,所有用户可读权限
Id id2 = new Id("world", "anyone");
ACL acl2 = new ACL(ZooDefs.Perms.READ, id2);
acls.add(acl2);
// zk用admin认证,创建/test ZNode。
ZooKeeper zk = new ZooKeeper(
"host1:2181,host2:2181,host3:2181",
2000, null);
zk.addAuthInfo("digest", "admin:admin".getBytes());
zk.create("/test", "data".getBytes(), acls, CreateMode.PERSISTENT);
}
}
然而,ACL毕竟仅仅是访问控制,并非完善的权限管理,通过这种方式做多集群隔离,还有很多局限性:
(1)ACL并无递归机制,任何一个znode创建后,都需要单独设置ACL,无法继承父节点的ACL设置。
(2)除了ip这种scheme,digest和auth的使用对用户都不是透明的,这也给使用带来了很大的成本,很多依赖zookeeper的开源框架也没有加入对ACL的支持,例如hbase,storm