1 Zookeeper ACL
ZooKeeper的權限管理亦即ACL控制功能通過Server、Client兩端協調完成:
Server端:
一個ZooKeeper的節點(znode)存儲兩部分內容:數據和狀態,狀態中包含ACL信息。創建一個znode會產生一個ACL列表,列表中每個ACL包括:
l 驗證模式(scheme)
l 具體內容(Id)(當scheme=“digest”時,Id爲用戶名密碼,例如“root:J0sTy9BCUKubtK1y8pkbL7qoxSw=”)
l 權限(perms)
1.1 scheme
ZooKeeper提供瞭如下幾種驗證模式(scheme):
l digest:Client端由用戶名和密碼驗證,譬如user:password,digest的密碼生成方式是Sha1摘要的base64形式
l auth:不使用任何id,代表任何已確認用戶。
l ip:Client端由IP地址驗證,譬如172.2.0.0/24
l world:固定用戶爲anyone,爲所有Client端開放權限
l super:在這種scheme情況下,對應的id擁有超級權限,可以做任何事情(cdrwa)
注意的是,exists操作和getAcl操作並不受ACL許可控制,因此任何客戶端可以查詢節點的狀態和節點的ACL。
節點的權限(perms)主要有以下幾種:
l Create 允許對子節點Create操作
l Read 允許對本節點GetChildren和GetData操作
l Write 允許對本節點SetData操作
l Delete 允許對子節點Delete操作
l Admin 允許對本節點setAcl操作
Znode ACL權限用一個int型數字perms表示,perms的5個二進制位分別表示setacl、delete、create、write、read。比如0x1f=adcwr,0x1=----r,0x15=a-c-r。
1.1.1 world scheme固定id爲anyone,表示對所有Client端開放權限:
[zk: localhost:2181(CONNECTED) 13]create /123 "123"
Created /123
[zk: localhost:2181(CONNECTED) 14]getAcl /123
'world,'anyone
: cdrwa
1.1.2 ip scheme設置可以訪問的ip地址(比如127.0.0.1)或ip地址段(比如192.168.1.0/16)
10.194.157.58這臺機器上創建/test並設置ip訪問權限
[zk: 10.194.157.58:2181(CONNECTED) 0]create /test "123"
Created /test
[zk: 10.194.157.58:2181(CONNECTED) 1]setAcl /test ip:10.194.157.58:crwda
cZxid = 0x740021e467
ctime = Wed Dec 02 18:09:09 CST 2015
mZxid = 0x740021e467
mtime = Wed Dec 02 18:09:09 CST 2015
pZxid = 0x740021e467
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: 10.194.157.58:2181(CONNECTED) 2]ls /test
[]
可以看到,本機是可以訪問的。
在10.205.148.152上登陸
[zk: 10.194.157.58:2181(CONNECTED) 1]ls /test
Authentication is not valid : /test
可以看到,連接的ip不在授權中,提示訪問錯誤。
1.1.3 digest scheme的id表示爲username:BASE64(SHA1(password))
[root@rocket zookeeper-server1]# cd/usr/local/zookeeper-server1/
[root@rocket zookeeper-server1]# pwd
/usr/local/zookeeper-server1
# 生成密文
[root@rocket zookeeper-server1]# java-cp./zookeeper-3.4.6.jar:./lib/log4j-1.2.16.jar:./lib/slf4j-log4j12-1.6.1.jar:./lib/slf4j-api-1.6.1.jarorg.apache.zookeeper.server.auth.DigestAuthenticationProvider test:test
test:test->test:V28q/NynI4JI3Rk54h0r8O5kMug=
創建acl
通過認證後,可以訪問數據:
[zk: localhost:2181(CONNECTED) 0]
[zk: localhost:2181(CONNECTED) 0] ls/test_acl
Authentication is not valid :/test_acl
[zk: localhost:2181(CONNECTED) 1]getAcl /test_acl
'digest,'test:V28q/NynI4JI3Rk54h0r8O5kMug=
: cdrwa
[zk: localhost:2181(CONNECTED) 2]addauth digest test:test
[zk: localhost:2181(CONNECTED) 3] ls/test_acl
[]
[zk: localhost:2181(CONNECTED) 4] get/test_acl
"test"
cZxid = 0x33
ctime = Wed Dec 02 00:10:47 PST 2015
mZxid = 0x33
mtime = Wed Dec 02 00:10:47 PST 2015
pZxid = 0x33
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
1.2 SuperDigest超級管理員
當設置了znode權限,但是密碼忘記了怎麼辦?還好Zookeeper提供了超級管理員機制。
一次Client對znode進行操作的驗證ACL的方式爲:
a) 遍歷znode的所有ACL:
i. 對於每一個ACL,首先操作類型與權限(perms)匹配
ii. 只有匹配權限成功才進行session的auth信息與ACL的用戶名、密碼匹配
b) 如果兩次匹配都成功,則允許操作;否則,返回權限不夠error(rc=-102)
備註:如果znode ACL List中任何一個ACL都沒有setAcl權限,那麼就算superDigest也修改不了它的權限;再假如這個znode還不開放delete權限,那麼它的所有子節點都將不會被刪除。唯一的辦法是通過手動刪除snapshot和log的方法,將ZK回滾到一個以前的狀態,然後重啓,當然這會影響到該znode以外其它節點的正常應用。
superDigest設置的步驟
修改zkServer.sh,加入super權限設置
-Dzookeeper.DigestAuthenticationProvider.superDigest=super:gG7s8t3oDEtIqF6DM9LlI/R+9Ss=
找到:_ZOO_DAEMON_OUT="$ZOO_LOG_DIR/zookeeper.out"該行內容,在其下方加入:ZOOMAIN="-Dzookeeper.DigestAuthenticationProvider.superDigest=super:gG7s8t3oDEtIqF6DM9LlI/R+9Ss= $ZOOMAIN"
重新啓動Zookeeper
# ./zkServer.sh restart
這時候
不使用test:test進行認證,而是使用super:super進行認證:
[zk: localhost:2181(CONNECTED) 0] ls/test_acl
Authentication is not valid :/test_acl
[zk: localhost:2181(CONNECTED) 1]addauth digest super:super
[zk: localhost:2181(CONNECTED) 2] ls/test_acl
[]
[zk: localhost:2181(CONNECTED) 3] get/test_acl
"test"
cZxid = 0x33
ctime = Wed Dec 02 00:10:47 PST 2015
mZxid = 0x33
mtime = Wed Dec 02 00:10:47 PST 2015
pZxid = 0x33
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
認證完畢後執行:
[zk: localhost:2181(CONNECTED) 3] setAcl/test_acl world:anyone:crwda 修改爲任何人都擁有該節點所有權限
1.3 ACL機制的缺陷
然而,ACL畢竟僅僅是訪問控制,並非完善的權限管理,通過這種方式做多集羣隔離,還有很多侷限性:
ACL並無遞歸機制,任何一個znode創建後,都需要單獨設置ACL,無法繼承父節點的ACL設置。
除了ip這種scheme,digest和auth的使用對用戶都不是透明的,這也給使用帶來了很大的成本,很多依賴zookeeper的開源框架也沒有加入對ACL的支持,例如hbase,storm。
2 Zookeeper quota
ZooKeeper quota機制支持節點個數(znode)和空間大小(字節數)。
[zk: localhost:2181(CONNECTED) 2]create /test_quota "12345"
Created /test_quota
[zk: localhost:2181(CONNECTED) 3]listquota /test_quota
absolute path is/zookeeper/quota/test_quota/zookeeper_limits
quota for /test_quota does not exist.
# 這裏看到quota還沒有設置
[zk: localhost:2181(CONNECTED) 4]setquota -n 5 /test_quota
Comment: the parts are option -n val5 path /test_quota
# -n表示設置znode count限制,這裏表示/test_quota這個path下的znode count個數限制爲5(包括/test_quota本身)
# -b 表示設置znode數據的字節大小限制,這裏不做演示了,有興趣的同學下去自己實驗
[zk: localhost:2181(CONNECTED) 5]listquota /test_quota
absolute path is/zookeeper/quota/test_quota/zookeeper_limits
Output quota for /test_quotacount=5,bytes=-1 # 限制znodecount爲5
Output stat for /test_quotacount=1,bytes=7 # 目前znode count爲1
[zk: localhost:2181(CONNECTED) 3]create /test_quota/0 "0"
Created /test_quota/0
[zk: localhost:2181(CONNECTED) 6]create /test_quota/1 "1"
Created /test_quota/1
[zk: localhost:2181(CONNECTED) 7]create /test_quota/2 "2"
Created /test_quota/2
[zk: localhost:2181(CONNECTED) 8]create /test_quota/3 "3"
Created /test_quota/3
[zk: localhost:2181(CONNECTED) 9]create /test_quota/4 "4"
Created /test_quota/4
# 上面新建了多個znode
看zookeeper的日誌,發現有Quotaexceeded的日誌,這裏要說明一下zookeeper的Quota機制是比較溫和的,即使超限了,只是在日誌中報告一下,並不會限制Client的行爲,Client可以繼續操作znode。
在實際項目中,Client可以查看/zookeeper/quota目錄下的數據來確定是否超出quota限制,由此來做一些告警。
[zk: localhost:2181(CONNECTED) 4] get/zookeeper/quota/test_quota/zookeeper_limits
count=5,bytes=-1
[zk: localhost:2181(CONNECTED) 5] get/zookeeper/quota/test_quota/zookeeper_stats
count=7,bytes=25