ZooKeeper zkclient ACL 訪問控制列表

存在的必要性

zk做爲分佈式架構中的重要中間件,通常會在上面以節點的方式存儲一些關鍵信息,默認情況下,所有應用都可以讀寫任何節點,在複雜的應用中,這不太安全,ZK通過ACL機制來解決訪問權限問題,詳見官網文檔:http://zookeeper.apache.org/doc/r3.4.6/zookeeperProgrammers.html#sc_ZooKeeperAccessControl

設計架構

acl 通過 [scheme:id:permissions] 構成

 

ZK的節點有5種操作權限:

權限組合字符串

縮寫 crdwa 
CREATE:創建子節點 
READ:獲取節點、子節點 
WRITE:設置節點數據 
DELETE:刪除子節點 
ADMIN:設置權限

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

 

4種身份的認證方式:

  • world: world下只有一個 id,即只有一個用戶,也就是 anyone,組合寫法爲:world:anyone:[permissions]
  • auth: 代表認證登錄,需要註冊用戶有權限,形式爲:auth:user:password:[permissions],(作用: 1: 通過addauth digest user:pwd 來認證用戶,2 :可以在1之後,設置節點acl權限使用。)
  • digest: 需要對密碼加密才能訪問,digest:username:BASE64(SHA1(password)):[permissions] 
    QQ截圖20180713085219.png

  • ip: 設置爲指定的 ip,此時對 ip 訪問進行限制,ip:192.168.1.1:[permissions]

  • super: 代表超級管理員,擁有所有的權限

id: 認證對象

對象: 根據schema 的不同而不同。

IP對象 :ip:192.168.1.1

auth 對象: auth:user1:pass1

digest 對象  digest:user1 :base64(sha1("pass1"))

 

測試示例:

測試功能點:1默認所有的節點都是world:anyone 的訪問控制權限。

Cli命令行下可以這樣測試:

通過getAcl命令可以發現,剛創建的節點,默認是 world,anyone的認證方式,具有cdrwa所有權限

測試功能點:2 可以通過setAcl 設置權限 ,getAcl 獲取權限,獲取權限得到的祕鑰都是加密過的。設置權限之後,get 方法獲取某個path 下的數據,就需要 先認證再獲取了,認證是通過addauth 命令實現的。

先給/test增加了user1:+owfoSBn/am19roBPzR1/MfCblE的只讀(r)權限控制,

說明:setAcl /test digest:用戶名:密碼:權限 給節點設置ACL訪問權限時,密碼必須是加密後的內容,這裏的+owfoSBn/am19roBPzR1/MfCblE=,對應的原文是12345 (至於這個密文怎麼得來的,後面會講到,這裏先不管這個),設置完Acl後,可以通過

getAcl /節點路徑 查看Acl設置

然後get /test時,提示認證無效,說明訪問控制起作用了,接下來:

addauth digest user1:12345 給"上下文"增加了一個認證用戶,即對應剛纔setAcl的設置

然後再 get /test 就能取到數據了

最後 delete /test 成功了!原因是:根節點/默認是world:anyone:crdwa(即:全世界都能隨便折騰),所以也就是說任何人,都能對根節點/進行讀、寫、創建子節點、管理acl、以及刪除子節點(再次映證了ACL中的delete權限應該理解爲對子節點的delete權限)

測試功能點:3  setAcl /path digest這種方式,必須輸入密碼加密後的值,這在cli控制檯上很不方便,所以可以先認證上下文,然後使用 setacl path 明文權限   做權限設置。

注意加框的部分,先用addauth digest user1:12345 增加一個認證用戶,然後用 setAcl /test auth:user1:12345:r 設置權限,跟剛纔的效果一樣,但是密碼這裏輸入的是明文,控制檯模式下手動輸入更方便。

 

加密規則

 

好了,揭開加密規則:

1

2

3

4

5

6

7

static public String generateDigest(String idPassword)

        throws NoSuchAlgorithmException {

    String parts[] = idPassword.split(":"2);

    byte digest[] = MessageDigest.getInstance("SHA1").digest(

            idPassword.getBytes());

    return parts[0] + ":" + base64Encode(digest);

}

就是SHA1加密,然後base64編碼  

 

權限控制和目錄的關係

最後:關於多級節點之間的ACL,並非繼承關係,但是也有些一聯繫,這是初次接觸ACL中比較難理解的地方:

從這張圖上可以發現,子節點/a/b的控制權限範圍(全世界都能做任何事)可以超出父節點的範圍(僅限:user-a:pwd:a具有read/admin權限)

繼續,看上面的這4條紅線標註的地方,從上向下一個個解釋:

紅線1:因爲/a只有user-a:pwd-a有ra權限,即:沒用戶具有c(create)權限,所以不能創建子節點

紅線2:因爲/a/b爲world:anyone:cdrwa權限,即無限制,所以在/a/b下創建子節點b1,地球人已經無法阻止,創建成功

紅線3:給/a/b/b1指定了user-b1:pwd-b1的da權限(即:delete+admin)

(注:重溫下前面提到的setAcl 二種模式,

一種是setAcl /path digest:username:encrypedpwd:crwda 用這種方式時,encrypedpwd用戶必須是密文,

另一種方式是先addauth digest:usrname:password 先把授權信息加入上下文,這裏password用的是明文,然後再setAcl /pathauth:username:password:crdwa

所以如果在cli控制檯測試,強烈建議用第二種方式,否則象上圖中的方式用錯了方式,pwd-b1在zk中被認爲是密文,要解密出來幾乎不可能,所以設置後,相當於這個節點就廢了,因爲你不知道密碼,要操作該節點時,提供不了正確的認證信息)

紅線4:還是剛纔的理由,因爲/a/b爲world:anyone:cdrwa,沒有限制,所以刪除其下的子節點不受阻擋。

從上圖可以看出,無法get父節點的內容,但是可以get子節點的內容,再次說明父、子節點的權限沒直接關係,但是做delete時,上面的例子卻遇到了麻煩:

想刪除/a/b時,由於父節點/a的ACL列表裏,只有ra權限,沒有d權限,所以無法刪除子節點。想刪除/a時,發現下面還有子節點b,節點非空無法刪除,所以這個示例就無解了(因爲根據前面的操作,密碼也還原不出來,也就無法修改ACL屬性),而根節點/也無法刪除,解決辦法,只能到data目錄裏清空所有數據,再重啓zk,但是這樣就相當於所有數據全扔了,所以在設計ACL時,對於delete權限,要謹慎規劃,在測試zk集羣上做好測試,再轉到生產環境操作。

最後給一些權限組合的測試結果:

要修改某個節點的ACL屬性,必須具有read、admin二種權限

要刪除某個節點下的子節點,必須具有對父節點的read權限,以及父節點的delete權限

 

ACL 使用場景

  1. 開發、測試環境分離,開發者無權操作測試庫節點
  2. 生產環境控制指定 ip 的服務可以訪問相關節點,防止混亂

java 實現:

注意zk 連接之後,做了一個權限認證,這個認證可以保證後續所有操作都是OK的

 

java權限擴展

儘管ZooKeeper已經爲我們提供了上述的四種權限模式,同時也提供給我們能夠自定義自己權限的方式——實現接口 
org.apache.zookeeper.server.auth.AuthenticationProvider 
- 啓動參數配置 
在ZooKeeper啓動參數中配置類似於如下的系統屬性 
-Dzookeeper.authProvider.1=com.zkbook.CustomAuthenticationProvider 
- 配置文件配置 
在zoo.cfg配置文件中配置類似於如下的配置項 
authProvider.1=com.zkbook.CustomAuthenticationProvider

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章