Zookeeper ACL
1. 前言
經(jīng)過前面幾節(jié)的學習,我們了解了基于 Zookeeper 的 Znode 和 Watch 可以實現(xiàn)很多業(yè)務場景,使用 Zookeeper 的 Java 客戶端對 Znode 的操作也非常方便。如果我們對 Znode 操作失誤,導致數(shù)據(jù)丟失,那么我們的應用也會受到影響,所以我們需要對 Znode 的操作加以控制。在 Zookeeper 中就是使用 Access Control Lists 訪問控制列表的方式來避免這種情況的發(fā)生。本節(jié)我們就來介紹 Zookeeper ACL 的實現(xiàn)以及 ACL 的實現(xiàn)原理。
2. Zookeeper ACL 組成
ACL 全稱 Access Control Lists,訪問控制列表。一個 Znode 的 ACL 可以分為 3 部分:
ACL 就是由以上 3 部分組成 Scheme:ID:Permission 這種形式的訪問控制信息,接下來我們來接介紹這 3 部分分別代表什么意思:
- 授權模式 Scheme: 授權模式 Scheme 就是選擇 Zookeeper 分配權限的方式,我們可以選擇的授權方式有 6 種:
- IP : 我們可以使用 IP 或 IP 段來對授權對象進行授權;
- HOST : 我們可以使用主機名的后綴來對授權對象進行授權,如果我們設置的 host 為 imooc.com,就可以匹配 coding.imooc.com,class.imooc.com;
- Auth : 給所有的認證用戶授權,需要使用
addauth digest username:password
命令添加認證用戶,Zookeeper 會把密碼使用 SHA-1 和 BASE64 算法進行加密; - Digest : 使用用戶名和密碼的方式驗證,不需要使用
addauth
添加認證用戶,需要手動使用SHA-1 和 BASE64 算法對密碼進行加密; - World : 默認權限
world:anyone:cdrwa
,任何人都可以對節(jié)點做任意操作。 - Super : 超級權限,授權對象可以對節(jié)點做任意操作;
- 授權對象 ID: 授權對象的意思就是我們要把 Scheme 設置的權限授權給誰。
- 如果我們設置的 Scheme 是 Auth ,那么授權對象就是所有使用
addauth digest username:password
命令添加認證用戶,那么我們在設置 ACL 時就不需要寫入授權對象了,例如:auth::crwda
; - 如果我們設置的 Scheme 是 Digest ,那么授權對象就是用戶名和被加密后的密碼,例如:
digest:mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=:crwda
;
- 如果我們設置的 Scheme 是 Auth ,那么授權對象就是所有使用
- 權限信息 Permission: 權限信息是指對 Znode 操作的權限,一共有 5 種操作權限,分別是:
- Create 節(jié)點創(chuàng)建權限: 授權對象可以在該節(jié)點下創(chuàng)建子節(jié)點;
- Read 節(jié)點數(shù)據(jù)讀取權限: 授權對象可以讀取該節(jié)點的 data 以及其子節(jié)點的 stat 和 ACL;
- Write 節(jié)點數(shù)據(jù)寫入權限: 授權對象可以更新該節(jié)點的 data;
- Delete 節(jié)點刪除權限: 授權對象可以刪除該節(jié)點的子節(jié)點;
- Admin 節(jié)點 ACL修改權限: 授權對象可以修改節(jié)點的 ACL 權限信息。
我們在設置權限信息時使用簡寫的方式,也就是使用權限信息的小寫首字母 crwda
來表示每一種操作,需要哪種權限信息就寫上哪種簡寫即可。
介紹完 ACL 的組成,接下來我們來使用 Zookeeper 的客戶端來實現(xiàn) ACL 訪問控制。
3. Zookeeper ACL 實現(xiàn)
在這里我們使用 zkCli.sh 命令行客戶端的方式來設置節(jié)點的 ACL 信息。
3.1 命令行客戶端設置 ACL
我們使用 Zookeeper 的客戶端 zkCli 命令行工具來設置節(jié)點的 ACL ,使用 zkCli.sh 連接 Zookeeper 服務端后,然后查看節(jié)點的 ACL 信息:
# 創(chuàng)建 /imooc
[zk: localhost:2181(CONNECTED) 1] create /imooc
# 創(chuàng)建成功
Created /imooc
# 查詢 /imooc 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 2] getAcl /imooc
# 輸出 ACL
'world,'anyone
: cdrwa
我們可以發(fā)現(xiàn),imooc 節(jié)點的 ACL 信息為默認的 world:anyone:cdrwa
.
接下來我們使用 Auth 的方式改變該節(jié)點的 ACL 設置:
# 添加認證用戶 mooc,密碼為 mooc
[zk: localhost:2181(CONNECTED) 3] addauth digest mooc:mooc
# 給 /imooc 節(jié)點設置 ACL,驗證模式為 auth,授權對象為所有認證用戶,所以可以不用填寫參數(shù),權限信息為所有操作
[zk: localhost:2181(CONNECTED) 4] setAcl /imooc auth::cdrwa
# 查看 /imooc 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 5] getAcl /imooc
# 輸出 ACL
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
我們可以看到 imooc 節(jié)點的 ACL 信息已經(jīng)修改成功,密碼也被加密了。接下來我們使用 Digest 的方式來設置節(jié)點的 ACL :
# 給 /imooc 節(jié)點設置 ACL,驗證模式為 digest
# 用戶名為 mooc,密碼是被加密后的 mooc,加密方式為 BASE64(SHA1(mooc)),權限信息為所有操作
[zk: localhost:2181(CONNECTED) 6] [zk: localhost:2181(CONNECTED) 6] setAcl /imooc digest:mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=:cdrwa
# 查看 /imooc 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 7] getAcl /imooc
# 輸出 ACL
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
我們可以發(fā)現(xiàn),使用 Auth 和 Digest 設置的 ACL 信息是相同的,都是基于 Digest 的授權模式,它們的區(qū)別是:
- Auth 需要在設置 ACL 之前添加認證用戶,并且無需手動加密,它的授權范圍是所有的使用
addauth digest username:password
命令添加的用戶。 - Digest 不需要提前添加認證用戶,但是需要自己完成密碼的加密,而且授權范圍只有當前設置的用戶。
Tips: 我們需要注意,當前客戶端添加的認證用戶只針對當前客戶端有效,客戶端斷開連接后也需要重新進行認證。
如果此時客戶端斷開連接,再重新連接,或者新開一個客戶端進行操作,訪問節(jié)點可能會出現(xiàn)以下錯誤:
[zk: localhost:2181(CONNECTED) 1] get /imooc
# 錯誤 1
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /imooc
[zk: localhost:2181(CONNECTED) 2] getAcl /imooc
# 錯誤 2
Authentication is not valid : /imooc
此時我們需要重新使用 addauth digest username:password
來對新的客戶端添加認證用戶,才可以訪問有 ACL 權限的節(jié)點。
# 添加認證用戶,用戶名密碼和設置 ACL 時的一致
[zk: localhost:2181(CONNECTED) 3] addauth digest mooc:mooc
[zk: localhost:2181(CONNECTED) 4] get /imooc
null
[zk: localhost:2181(CONNECTED) 5] getAcl /imooc
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
Tips: 如果是密碼設置錯誤導致對節(jié)點的訪問無權限,我們可以在 zoo.cfg 配置文件中加入 skipACL=yes,跳過 ACL 驗證,重啟服務后再修改 ACL 信息或者刪除錯誤節(jié)點。本設置不建議在生產環(huán)境下使用!
上面的設置方式都是針對當前節(jié)點的 ACL 的設置,一個一個的對每個節(jié)點去設置它們的 ACL 信息是一件非常繁瑣的事情,所以我們可以使用 -R 參數(shù)來遞歸設置子節(jié)點的 ACL 信息:
# 創(chuàng)建子節(jié)點 /imooc/mooc
[zk: localhost:2181(CONNECTED) 8] create /imooc/mooc
# 創(chuàng)建子節(jié)點 /imooc/mooc 成功
Created /imooc/mooc
# 創(chuàng)建子節(jié)點 /imooc/mooc/wiki
[zk: localhost:2181(CONNECTED) 9] create /imooc/mooc/wiki
# 創(chuàng)建子節(jié)點 /imooc/mooc/wiki 成功
Created /imooc/mooc/wiki
# 使用 digest 設置 /imooc 節(jié)點的 ACL,使用 —R 來遞歸設置子節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 10] setAcl -R /imooc digest:mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=:cdrwa
# 查看 /imooc 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 11] getAcl /imooc
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
# 查看 /imooc/mooc 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 12] getAcl /imooc/mooc
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
# 查看 /imooc/mooc/wiki 節(jié)點的 ACL 信息
[zk: localhost:2181(CONNECTED) 13] getAcl /imooc/mooc/wiki
'digest,'mooc:0xEep90zjLm6hbWMlQ2BGbaQWzI=
: cdrwa
我們發(fā)現(xiàn) imooc 的 ACL 信息和它的子節(jié)點的 ACL 信息都是相同的,說明我們使用 -R
遞歸設置子節(jié)點的 ACL 信息成功了。
成功的實現(xiàn)了節(jié)點 ACL 的設置之后,接下來我們來講解 Zookeeper ACL 實現(xiàn)的原理。
4. Zookeeper ACL 原理
由于 Zookeeper 是 C/S 架構,所以 Zookeeper ACL 的實現(xiàn)原理也分為兩部分,Zookeeper 客戶端和 Zookeeper 服務端。我們首先從 Zookeeper 客戶端開始介紹。
4.1 Zookeeper 客戶端處理 ACL 請求
在 Zookeeper 客戶端中,當我們使用 addauth digest mooc:mooc
命令來添加認證用戶信息時,Zookeeper 客戶端會使用 ClientCnxn 客戶端類的 addAuthInfo 方法來封裝請求信息,把請求類型包裝成權限類請求,封裝完畢后發(fā)送給服務端。
// 添加認證信息,參數(shù)一:授權類型,參數(shù)二:認證信息的字節(jié)數(shù)組
public void addAuthInfo(String scheme, byte[] auth) {
// 判斷當前客戶端狀態(tài)
if (this.state.isAlive()) {
// 封裝認證信息 scheme:digest
this.authInfo.add(new ClientCnxn.AuthData(scheme, auth));
// 封裝請求頭 -4為請求頭的xid,100為請求類型:auth
this.queuePacket(new RequestHeader(-4, 100), (ReplyHeader)null, new AuthPacket(0, scheme, auth), (Record)null, (AsyncCallback)null, (String)null, (String)null, (Object)null, (WatchRegistration)null);
}
}
簡單地介紹了 Zookeeper 客戶端處理權限類請求的過程,接下來就是 Zookeeper 服務端的處理過程了。
4.2 Zookeeper 服務端處理 ACL 請求
在 Zookeeper 服務端接收到 Zookeeper 客戶端發(fā)送過來的請求后,首先解析請求頭,識別請求的類型,發(fā)現(xiàn)客戶端的請求類型是 auth 時,也就是權限類請求時,Zookeeper 會使用 scheme 來判斷授權類型,找具體處理授權的實現(xiàn)類,在實現(xiàn)類中來進行權限驗證,然后把認證用戶保存到認證信息的集合中。
在 Zookeeper 客戶端使用剛才添加的認證用戶信息來進行節(jié)點操作時,向 Zookeeper 服務端發(fā)送權限請求,服務端解析完成請求類型和授權類型后,再去具體的認證信息集合中去匹配請求中攜帶的授權信息,匹配成功則執(zhí)行具體操作,匹配不到則說明該請求無授權,返回 NoAuthException 異常信息。
5. 總結
在本節(jié)內容中我們學習了 Zookeeper 的 ACL 訪問控制列表的組成,并使用命令行客戶端的方式進行了實現(xiàn),最后簡單的介紹了以下 Zookeeper 處理 ACL 請求的過程。以下是本節(jié)內容總結:
- Zookeeper ACL 的組成
- 使用命令行客戶端實現(xiàn) ACL
- Zookeeper ACL 的原理