原文鏈接:https://www.jianshu.com/p/392248ab27f4
對zookeeper設置ACL屬性
我們以zkCli為例,來說明zookeeper對ACL的設置。
使用zkCli時,ACL的格式由<schema>:<id>:<acl>三段組成。
- schema:可以取下列值:world, auth, digest, host/ip
- id: 標識身份,值依賴於schema做解析。
- acl:就是權限:cdwra分別表示create, delete,write,read, admin
注意:zookeeper對權限的控制是znode級別的,不具有繼承性,即子節點不繼承父節點的權限。這種設計在使用上還是有缺陷的,因為很多場景下,我們還是會把相關資源組織一下,放在同一個路徑下面,這樣就會有對一個路徑統一授權的需求。
- schema world
這是默認方式,表示沒有認證。當創建一個新的節點(znode),而又沒有設置任何權限時,就是這個值,例如:
[zk: localhost:2181(CONNECTED) 18] create /noacl 'noacl' Created /noacl [zk: localhost:2181(CONNECTED) 19] getAcl /noacl 'world,'anyone : cdrwa
看到/noacl的ACL屬於就是world schema的,因為它沒有設置ACL屬性,這樣任何人都可以訪問這個節點。
如果要手工設置這個屬性,那么此時的id域只允許一個值,即anyone,格式如下:
setAcl /newznode world:anyone:crdwa
- schema auth
這種授權不針對任何特點ID,而是對所有已經添加認證的用戶,換句話說,就是對所有已經通過認證的用戶授權。
用法如下:
addauth digest <user>:<password> setAcl <path> auth:<id>:<acl>
注意:
-
- 比須要先添加認證用戶,否則會失敗呢。如下所示:
[zk: localhost:2181(CONNECTED) 0] create /test 'test'
[zk: localhost:2181(CONNECTED) 1] setAcl /test auth::crdwa
Acl is not valid : /test
-
- setAcl命令中的id域是被忽略的,可以填任意值,或者空串,例如:`setAcl <path> auth::crdwa。因為這個域是忽略的,會把所有已經添加的認證用戶都加進來。
舉例:
[zk: localhost:2181(CONNECTED) 2] addauth digest tom1:tom1 [zk: localhost:2181(CONNECTED) 3] addauth digest tom2:tom2 [zk: localhost:2181(CONNECTED) 4] addauth digest tom3:tom3 [zk: localhost:2181(CONNECTED) 5] setAcl /test auth:tom2:crdwa [zk: localhost:2181(CONNECTED) 6] getAcl /test 'digest,'tom1:ben+k/3JomjGj4mfd4fYsfM6p0A= : cdrwa 'digest,'tom2:2iJM00A7+qkeKdEXt8Bhgq+IACw= : cdrwa 'digest,'tom3:TAZPWLs6IaYRS8mlvcfyCOwyBJ8= : cdrwa
這個例子中,我們先添加了三個認證用戶tom1,tom2,tom3,然后通過setAcl設置ACL,命令中指定了id為tom2,根據前面的說法,這個id值是被忽略的,寫任何值,甚至空值也得到一樣的結果。我們看到最后getAcl查詢出來的結果包含所有前面添加的三個認證用戶。
補充說明:zkCli的命令addauth digest user:pwd是用來添加當前上下文中的認證用戶的:
addauth digest user1:password1(明文)
其實我不是很理解這個功能,難道在一個會話(session)里可以添加多個認證用戶嗎,那驗證的時候按哪一個算呢;如果不同的用戶有不同的授權會導致授權沖突嗎?以誰為准?
幾點總結:
- auth的id值是無效的,表示給所有認證用戶設置acl權限。
1.1. 認證用戶的添加,通過addauth命令(addauth digest <username>:<password>),只在當前會話(session)有效。 - 當使用addauth命令添加多個認證用戶后,再用auth setAcl來設置acl時,那么所有之前addauth的用戶都被會加入到acl中。
- 如果在當前會話中還沒有認證過的用戶就使用auth setAcl來設置acl權限時會失敗,前面已經討論過。
[zk: localhost:2181(CONNECTED) 1] setAcl /test auth::crdwa
Acl is not valid : /test
- 在auth setAcl之后再使用addauth添加的認證用戶是沒有acl權限的,必須重新執行auth setAcl來設置權限。
- 使用addauth添加的認證用戶只在當前會話(session)有效,如果此時在另外一個會話中,不添加對應的認證用戶,那么就沒有相應訪問權限的,而且如果再使用auth setAcl來設置acl權限,則會覆蓋之前的acl權限信息,而且只會針對當前會話中的認證用戶來設置acl權限。
所以這種授權方式更傾向於用作測試開發環境,而不是產品環境中。
- schema digest
這就是最普通的用戶名:密碼的驗證方式,在一般業務系統中最常用。
格式如下:
setAcl <path> digest:<user>:<password(密文)>:<acl>
和schema auth相比,有兩點不同:
- 第一不需要預先添加認證用戶(但是在zkCli訪問的時候,肯定還是要添加認證用戶的)。
- 第二密碼是經過sha1及base64處理的密文。
密碼可以通過如下shell的方式生成:
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
例如:
echo -n root:root | openssl dgst -binary -sha1 | openssl base64
qiTlqPLK7XM2ht3HMn02qRpkKIE=
或者可以使用zookeeper的庫文件生成:
java -cp /zookeeper-3.4.13/zookeeper-3.4.13.jar:/zookeeper-3.4.13/lib/slf4j-api-1.7.25.jar \ org.apache.zookeeper.server.auth.DigestAuthenticationProvider \ root:root root:root->root:qiTlqPLK7XM2ht3HMn02qRpkKIE=
輸出的root:jalRr+knv/6L2uXdenC93dEDNuE=就是傳遞給setAcl使用的id串。
setAcl /test2 digest:root:jalRr+knv/6L2uXdenC93dEDNuE=:rwdca
注意,只有通過zkCli.sh設置digest的ACL時id才需要密文,而通過zookeeper的客戶端設置digest的ACL時對應的auth數據是明文。這個屬於編碼實現的問題了。
和auth比較,digest有如下特性:
- setAcl不需要事先添加認證用戶。
- 授權是針對單個特定用戶。
- setAcl使用的密碼不是明文,是sha1摘要值,無法反推出用戶密碼內容。
- schema host/ip
就是客戶機地址,或者是主機名、或者是IP地址。
主機名可以是單個主機名,也可以是域名。IP可以是單個IP地址,也可以是IP地址段,比如ip:192.168.1.0/16。
這個不細說了,比較簡單,也沒有驗證過。
- super用戶
設置一個超級用戶,這個超級用戶的設置必須在zookeeper內部,zookeeper啟動之前設置好。在這種scheme情況下,超級用戶具有超級權限,可以做任何事情(cdrwa),不需要授權。
5.1 設置zookeeper環境變量SERVER_JVMFLAGS:
export SERVER_JVMFLAGS="-Dzookeeper.DigestAuthenticationProvider.superDigest=root:qiTlqPLK7XM2ht3HMn02qRpkKIE="
5.2 重啟zookeeper
創建/test節點,並且設置acl為jerry1用戶。
[zk: localhost:2181(CONNECTED) 0] create /test 'test'
Created /test
[zk: localhost:2181(CONNECTED) 1] setAcl /test digest:jerry1:dJJW56m9FIOfUDDHVC5wVWNsFEo=:rwdca
[zk: localhost:2181(CONNECTED) 2] getAcl /test
'digest,'jerry1:dJJW56m9FIOfUDDHVC5wVWNsFEo=
: cdrwa
5.3 添加認證用戶tom
[zk: localhost:2181(CONNECTED) 3] addauth digest tom:tom
5.4 訪問節點/test
[zk: localhost:2181(CONNECTED) 4] get /test Authentication is not valid : /test
這時失敗,因為tom用戶沒有權限。
5.3 添加認證用戶root
[zk: localhost:2181(CONNECTED) 6] addauth digest root:root
5.4 再次訪問節點/test
[zk: localhost:2181(CONNECTED) 6] get /test
test
...
成功,雖然root也沒有在/test的acl列表里面(是有jerry1),但是也能訪問,因為root在zookeeper集群里面被配置成了超級用戶。
