ZooKeeper 作為一個分布式協調架構,内部存儲的都是一些分布式系統運作時狀态的中繼資料,尤其是一些涉及到,
分布式鎖
和
master選舉
等應用場景的資料,資料的通路權限涉及到 ZooKeeper 運作時安全。為了保障 ZooKeeper 的資料安全,提供了一套完整的
分布式協調
權限控制機制來保障資料的安全。
ACL(Access Control List)
權限 ACL 介紹
ACL 的實作和 UNIX 的實作非常相似:它
采用權限位來控制哪些操作被允許,哪些操作被禁止
。但是和标準的 UNIX 權限不同的是,Znode 沒有限制使用者(user,即檔案的所有者),組(group)和其他(world)。Zookeepr 是沒有所有者的概念的。
每個 ZNode 的ACL是獨立的,且子節點不會繼承父節點的ACL
。例如:Znode /app對于 ip 為172.16.16.1隻有隻讀權限,而/app/status是world可讀,那麼任何人都可以擷取 /app/status。是以在 Zookeeper 中權限是沒有繼承和傳遞關系的,
每個Znode 的權限都是獨立存在的
。
Zookeeper 支援可插拔的權限認證方案,分為三個次元:scheme,user,permission。通常表示為
[scheme:id:permissions]
,其中 Scheme 表示使用何種方式來進行通路控制(使用何種權限驗證機制),Id代表使用者,Permission表示有什麼權限(權限組合字元串)。下面分别說說這三個次元:
一個 ZooKeeper 的節點( znode )存儲兩部分内容:資料和狀态,狀态中包含 ACL 資訊。建立一個 znode 會産生一個 ACL 清單,清單中每個 ACL 包括以上三個次元。
ACL 的構成-scheme(權限模式)
scheme 有以下幾種類型:
-
:world下隻有一個id,即隻有一個使用者,也就是anyone,那麼組合的寫法就是 world:anyone:[permissions]world
-
:當設定為ip指定的ip位址,此時限制ip進行通路,比如 ip:192.168.77.130:[permissions]。也可以通過配置IP網段的方式,例如 “ip:192.168.28.1/24:[permissions]”,表示針對192.168.28.*整個IP段進行權限控制。ip
-
:代表認證登入,需要注冊使用者擷取權限後才可以登入通路,形式為 auth:userpassword:[permissions]auth
-
:需要對密碼加密才能通路,組合形式為:digest:username:BASE64(SHA1(password)):[permissions]。具體的實作是由DigestAuthenticationProvider.generateDigest()方法來保證的。digest
- auth 與 digest 的差別就是,前者使用明文密碼進行登入,後者使用密文密碼進行登入。
與setAcl /path auth:lee:lee:cdrwa
是等價的,在通過setAcl /path digest:lee:BASE64(SHA1(password)):cdrwa
後都能操作指定節點的權限。在實際情況中,digest要更為常用一些。addauth digest lee:lee
- auth 與 digest 的差別就是,前者使用明文密碼進行登入,後者使用密文密碼進行登入。
-
:代表超級管理者,擁有所有的權限,可以操作ZooKeeper上的任意節點資料。super
注意的是, exists 操作和 getAcl 操作并不受 ACL 許可控制,是以任何用戶端可以查詢節點的狀态和節點的 ACL 。
ACL 的構成-id(授權對象)
對于不同的scheme,授權的對象是不同的:
- IP模式:授權對象通常是一個ip位址或者是一個ip段;
- Digest模式:授權對象通常是自定義中的username;
- World模式:授權對象是anyone;
- Super模式:授權對象和Digest中的相同;
ACL 的構成-permissions(權限)
權限字元串縮寫
crdwa
:
-
:建立子節點權限(允許對子節點 Create 操作);CREATE
-
:通路節點/子節點權限(允許對本節點 GetChildren 和 GetData 操作);READ
-
:設定節點資料權限(允許對本節點 SetData 操作);WRITE
-
:删除子節點權限(允許對子節點 Delete 操作);DELETE
-
:管理者權限(允許對本節點 setAcl 操作);ADMIN
ACL 指令
-
:擷取某個節點的ACL權限資訊;getAcl
-
:設定某個節點的ACL權限資訊;setAcl
-
:輸入認證授權資訊,注冊時輸入明文密碼(登入),但是在zk的系統裡,密碼是以加密後的形式存在的;addauth
ACL 指令行操作
ACL 指令行 world
使用 getAcl 指令擷取某個節點的acl權限資訊,示例:
[zk: localhost:(CONNECTED) ] create /testDir/testAcl test-data # 建立一個子節點
Created /testDir/testAcl
[zk: localhost:(CONNECTED) ] getAcl /testDir/testAcl # 擷取該節點的acl權限資訊
'world,'anyone # 預設為world
: cdrwa
使用 setAcl 指令設定某個節點的acl權限資訊,示例:
[zk: localhost:2181(CONNECTED) 2] setAcl /testDir/testAcl world:anyone:crwa # 設定該節點的acl權限
cZxid = 0x67
ctime = Tue Aug 28 13:12:29 CST 2018
mZxid = 0x67
mtime = Tue Aug 28 13:12:29 CST 2018
pZxid = 0x67
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: localhost:2181(CONNECTED) 3] getAcl /testDir/testAcl
'world,'anyone
: crwa # 設定成功後,該節點就少了d權限
[zk: localhost:2181(CONNECTED) 4] create /testDir/testAcl/xyz xyz-data # 建立子節點
Created /testDir/testAcl/xyz
[zk: localhost:2181(CONNECTED) 5] delete /testDir/testAcl/xyz # 删除該子節點
Authentication is not valid : /testDir/testAcl/xyz # 由于沒有d權限,是以提示無法删除
設定其他的權限也是如此,在此就不做示範了。
ACL 指令行 auth
使用 auth 來設定權限的時候,需要在 zk 裡注冊一個使用者才可以。示例:
[zk: localhost:2181(CONNECTED) 6] addauth digest user1:123456 # 需要先添加一個使用者
[zk: localhost:2181(CONNECTED) 7] setAcl /testDir/testAcl auth:user1:123456:crwa # 然後才可以拿着這個使用者去設定權限
cZxid = 0x67
ctime = Tue Aug 28 13:12:29 CST 2018
mZxid = 0x67
mtime = Tue Aug 28 13:12:29 CST 2018
pZxid = 0x69
cversion = 1
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 9
numChildren = 1
[zk: localhost:2181(CONNECTED) 8] getAcl /testDir/testAcl
'digest,'user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s= # 密碼是以密文的形式存儲的
: crwa
如果設定了權限後,再次進行設定,就可以不用加上使用者名和密碼了。而且就算是使用其他使用者進行設定,也隻會根據第一次設定的使用者來進行配置:
[zk: localhost:(CONNECTED) ] setAcl /testDir/testAcl auth::crw
[zk: localhost:(CONNECTED) ] setAcl /testDir/testAcl auth:test:test:crw
[zk: localhost:(CONNECTED) ] getAcl /testDir/testAcl
'digest,'user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s= # 依舊是第一次設定的使用者
: crw
ACL 指令行 digest
由于之前使用 auth 做實驗的時候已經登入了使用者 ,是以在使用 digest 做實驗前,需要先退出一下用戶端,再重新連接配接,這樣之前登入的使用者就會自動退出。退出使用者後才能使用 digest 設定權限,示例:
[zk: localhost:2181(CONNECTED) 2] create /names/testDigest digest-data # 建立子節點
Created /names/testDigest
[zk: localhost:2181(CONNECTED) 3] addauth digest user1:123456 # 添加使用者
[zk: localhost:2181(CONNECTED) 4] getAcl /names/testDigest
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 5] setAcl /names/testDigest digest:user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s=:crwa # 使用digest來設定權限
cZxid = 0x72
ctime = Tue Aug 28 14:37:05 CST 2018
mZxid = 0x72
mtime = Tue Aug 28 14:37:05 CST 2018
pZxid = 0x72
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 11
numChildren = 0
[zk: localhost:2181(CONNECTED) 6] getAcl /names/testDigest
'digest,'user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s=
: crwa
可以看到,digest 和 auth 除了一個使用明文一個使用密文之外,其他都是一緻的,是以它倆的差別就隻是密文和明文的差別。線上上環境中,一般使用 digest 比較多,因為密文安全一些。
ACL 指令行 ip
這種方式和限制 ip 是一樣的,就是設定隻允許某一個 ip 有權限操作。示例:
[zk: localhost:2181(CONNECTED) 7] create /names/testip ip-data # 建立子節點
Created /names/testip
[zk: localhost:2181(CONNECTED) 8] getAcl /names/testip
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 9] setAcl /names/testip ip:192.168.190.129:cdrwa # 使用ip來設定權限
cZxid = 0x74
ctime = Tue Aug 28 15:03:56 CST 2018
mZxid = 0x74
mtime = Tue Aug 28 15:03:56 CST 2018
pZxid = 0x74
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
[zk: localhost:2181(CONNECTED) 10] getAcl /names/testip
'ip,'192.168.190.129 # 隻允許這個ip擁有該節點的cdrwa權限
: cdrwa
[zk: localhost:2181(CONNECTED) 11] get /names/testip
Authentication is not valid : /names/testip # 由于本機的ip不是192.168.190.129,是以擷取失敗
ACL 指令行 super超級管理者
基本所有的系統都會擁有一個超級管理者使用者,zk也不例外。當我們給一些節點設定了權限,但是卻發現設定錯誤了,導緻節點無法正常通路,那麼這時候普通使用者是無法解決這種問題的,隻能使用超級管理者使用者來重新設定權限或删除節點。是以本節簡單示範一下,如何配置管理者使用者:
1、修改 zkServer.sh 增加super管理者
[root@study- /usr/local/zookeeper-./bin]# vim zkServer.sh # 找到nohup那一行,加入以下内容
"-Dzookeeper.DigestAuthenticationProvider.superDigest=user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s="
注:user1是使用者名,後面那一大串是加密後的密文密碼
如下圖:
2、修改完之後,需要重新開機zookeeper服務才能生效 3、使用超級管理者使用者
[[email protected] ~]# zkCli.sh
[zk: localhost:2181(CONNECTED) 9] ls /names/ip # ls一個無權限的節點
Authentication is not valid : /names/ip # 可以看到,權限不夠
[zk: localhost:2181(CONNECTED) 10] addauth digest user1:123456 # 登入超級管理者使用者,這裡登入用的是明文密碼
[zk: localhost:2181(CONNECTED) 11] ls /names/ip # 然後再次ls
[] # 這次就可以ls到了
[zk: localhost:2181(CONNECTED) 12] get /names/ip # 也可以get資訊
ip-data
cZxid = 0x51
ctime = Mon Apr 23 21:02:42 CST 2018
mZxid = 0x51
mtime = Mon Apr 23 21:02:42 CST 2018
pZxid = 0x51
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
[zk: localhost:2181(CONNECTED) 13] delete /names/testip # 删除節點也可以
ACL 的常用使用場景
- 開發/測試環境分離,開發者無權操作測試庫的節點,隻能讀取
- 生産環境上控制指定ip的服務可以通路相關的節點,防止混亂