Zookeeper ACL許可權配置及zkclient示例
zk做為分散式架構中的重要中介軟體,通常會在上面以節點的方式儲存一些關鍵資訊,預設情況下,所有應用都可以讀寫任何節點,在複雜的應用中,這不太安全,ZK通過ACL機制來解決訪問許可權問題,詳見官網文件:http://zookeeper.apache.org/doc/r3.4.6/zookeeperProgrammers.html#sc_ZooKeeperAccessControl
ZK的節點有5種操作許可權:
CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、刪、改、查、管理許可權,這5種許可權簡寫為crwda(即:每個單詞的首字元縮寫)
注:這5種許可權中,delete是指對子節點的刪除許可權,其它4種許可權指對自身節點的操作許可權
許可權 |
描述 |
setAcl中的簡寫 |
---|---|---|
write |
能夠設定znode的值 |
w |
read |
能夠讀取znode的值和列出它的children znode |
r |
create |
能夠建立children znode |
c |
delete |
能夠刪除children znode |
d |
admin |
能夠執行setAcl即設定訪問控制列表 |
a |
all |
所有許可權 |
wrcda |
身份的認證有4種方式:
world:預設方式,相當於全世界都能訪問
auth:代表已經認證通過的使用者(cli中可以通過addauth digest user:pwd 來添加當前上下文中的授權使用者)
digest:即使用者名稱:密碼這種方式認證,這也是業務系統中最常用的
ip:使用Ip地址認證
設定訪問控制:
啟動zookper後,使用zkCli進行操作
zkCli.cmd -server 127.0.0.1:2181
方式一:(推薦)
1)增加一個認證使用者
addauth digest 使用者名稱:密碼明文
eg.
addauth digest user1:password1
2)設定許可權
setAcl /path auth:使用者名稱:密碼明文:許可權
eg.
setAcl /test auth:user1:password1:cdrwa
3)檢視Acl設定
getAcl /path
方式二:
setAcl /path digest:使用者名稱:密碼密文:許可權
注:這裡的加密規則是SHA1加密,然後base64編碼。
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println(generateDigest("admin:12345"));;
}
static public String generateDigest(String idPassword)
throws NoSuchAlgorithmException {
String parts[] = idPassword.split(":", 2);
byte digest[] = MessageDigest.getInstance("SHA1").digest(
idPassword.getBytes());
return parts[0] + ":" + org.apache.commons.codec.binary.Base64.encodeBase64String(digest);
}
zkclient是zookeeper客戶端的一種實現,支援ACL許可權傳輸並訪問zookeeper節點。
maven依賴:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.6</version>
</dependency>
zkclient增加ACL許可權:
public ZkClient createACLClient(URL url) {
ZkClient client = new ZkClient(url.getBackupAddress());
/**
* 增加Zookeeper的ACL控制選項
*/
if (!StringUtils.isEmpty(url.getUsername()) && !StringUtils.isEmpty(url.getPassword())) {
StringBuffer auth = new StringBuffer(url.getUsername())
.append(":").append(url.getPassword());
client.addAuthInfo("digest", auth.toString().getBytes());
}
return client;
}