zk Acl權限:只有一個帳號有crdwa權限,匿名用戶只有r權限

原由

    最近在作多租戶改造,租戶使用的配置項都要放到zk上(如數據庫配置、redis配置、阿里oss配置、每一個租戶的域名配置等),每一個子系統去zk讀取配置。當配置信息改變時,經過zk的watch機制,給子系統發消息,子系統接收到消息以後,再去作相應的處理(如:租戶1的數據庫配置變了,就從新建立數據庫鏈接池)。html

    圖1:系統關係邏輯及問題描述java

問題描述:node

主要是隻讀的那些zkClient,不用帳號密碼,就能讀(r)到zk上的數據。而不是給子系統分配帳號密碼。redis

子系統訪問zk的時候,是不能帶帳號密碼的。數據庫

若是用digest 給子系統分配統一的一個帳號密碼,在代碼的層面是能夠實現的。apache

可是老大要求,子系統訪問zk的時候,不能帶着密碼。並且,只能有讀(r)權限。session

思路

注:這5種權限中,delete是指對子節點的刪除權限,其它4種權限指對自身節點的操做權限框架

使用命令看一下world的權限是cdrwa(也就是anyone擁有全部權限)spa

因此,忽然想到,能不能把world身份認證方式的默認權限設置成r,而admin的帳號分配給crdwa權限。.net

因而使用代碼:

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

相關文章
相關標籤/搜索