zk Acl权限:只有一个账号有所有权限,匿名用户只有读权限

起因

    最近在做多租户改造,租户使用的配置项都要放到zk上(如数据库配置、redis配置、阿里oss配置、每个租户的域名配置等),每个子系统去zk读取配置。当配置信息改变时,通过zk的watch机制,给子系统发消息,子系统接收到消息之后,再去做相应的处理(如:租户1的数据库配置变了,就重新创建数据库连接池)。

    图1:系统关系逻辑及问题描述

问题描述:

主要是只读的那些zkClient,不用账号密码,就能读(r)到zk上的数据。而不是给子系统分配账号密码。

子系统访问zk的时候,是不能带账号密码的。

如果用digest 给子系统分配统一的一个账号密码,在代码的层面是可以实现的。

但是老大要求,子系统访问zk的时候,不能带着密码。而且,只能有读(r)权限。

思路

注:这5种权限中,delete是指对子节点的删除权限,其它4种权限指对自身节点的操作权限

使用命令看一下world的权限是cdrwa(也就是anyone拥有所有权限)

所以,突然想到,能不能把world身份认证方式的默认权限设置成r,而admin的账号分配给crdwa权限。

于是使用代码:


    public void set(String path, String data) {
        createPathIfNotExists(path);
        zkClient.writeData(path, data);
    }

    /**
     * 如果path不存在,则创建。
     *
     * @param path
     */
    private void createPathIfNotExists(String path) {
        String id = null;
        try {
            id = generateDigest("admin:admin"); // admin用户的账号:密码
        } catch (NoSuchAlgorithmException e) {
            throw new RRException("zk生成idPassword失败。zkPassword=" + zkPassword + ",zkPassword=" + zkPassword);
        }
        // 创建znode时,同时设置Acl权限:
        List<ACL> acl = new ArrayList<>();
        acl.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", id)));
        acl.add(new ACL(ZooDefs.Perms.READ, new Id("world", "anyone")));
        createPersistentIfNotExists(path, acl);
    }

    private void createPersistentIfNotExists(String path, List<ACL> acl) {
        if (!zkClient.exists(path)) {
            zkClient.createPersistent(path, true, acl);
        }
    }

这样,world默认的权限就改为了readOnly的了:

参考

ZooKeeper 笔记(5) ACL(Access Control List)访问控制列表

zookeeper ACL使用

 然而,ACL毕竟仅仅是访问控制,并非完善的权限管理,通过这种方式做多集群隔离,还有很多局限性:

(1)ACL并无递归机制,任何一个znode创建后,都需要单独设置ACL,无法继承父节点的ACL设置。

(2)除了ip这种scheme,digest和auth的使用对用户都不是透明的,这也给使用带来了很大的成本,很多依赖zookeeper的开源框架也没有加入对ACL的支持,例如hbase,storm

Zookeeper API 和 Zkclient

2. session的超时问题:

  ZKClient框架里会经常看见一些while语句,是由这些while语句完成的,比如ZkClient.retryUntilConnected方法 
(感谢紫川的反馈,此条可能存在描述性问题。经校对:ZkClient貌似还是有对Session Expired 处理的,在ZkClient.processStateChanged方法中。虽然能重新连接,但是连接上是一个新的 session,原有创建的ephemeral znode(即临时节点)和watch会被删除,程序上你可能需要处理这个问题。欢迎大家提出意见,万分感谢)

    对上面引用的补充:zkClient重新连接之后,还会把通过org.I0Itec.zkclient.ZkClient#addAuthInfo方法设置的权限信息给删掉。也需要自己去处理这个问题。详情:

org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /nb-conf

猜你喜欢

转载自my.oschina.net/anxiaole/blog/1814143
zk