linux中的dhcp
1.認識一下控制命令
要了解ZooKeeper的ACL許可權控制,首先我們需要了解一下ZooKeeper客戶端的許可權控制的命令:
1、建立zk節點時,可以同時指定許可權資訊(可選)
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
2、根據路徑設定節點的許可權(對一個已存在的節點)
setAcl [-s] [-v version] [-R] path acl
3、根據路徑獲取節點的許可權
getAcl [-s] path
4、認證授權資訊的命令(auth格式為使用者名稱:密碼
, 密碼為明文密碼)
addauth scheme auth
那麼 create
setAcl
中 acl 應該是什麼樣的格式呢?
[zk: localhost:2181(CONNECTED) 0] create /test
Created /test
[zk: localhost:2181(CONNECTED) 1] setAcl /test acl
acl does not have the form scheme:id:perm
Acl is not valid : /test
- 首先,建立一個新節點
/test
- 然後,用
setAcl
為節點/test
設定許可權 - 接著,我們讀這段報錯
acl does not have the form scheme:id:perm
我們知道了 acl 應該由三部分組成:scheme, id, perm。
2. ACL 許可權控制
Zookeeper 的 ACL 許可權控制,可以控制節點的讀寫操作,保證資料的安全性,Zookeeper ACL 許可權設定分為 3 部分組成,分別是:許可權模式(Scheme)、授權物件(ID)、許可權資訊(Permission)。最終組成⼀條例如scheme:id:permission
格式的 ACL 請求資訊。
ZooKeeper 可以給每個節點設定不同的許可權控制。
2.1 許可權 Permission
首先,我們可能關心,對於某個資料節點,到底有哪些細分的許可權呢?
許可權就是指我們可以在資料節點上執⾏的操作種類(CRUD),如下所示:在 ZooKeeper 中已經定義好的許可權有 5 種:
- 資料節點(c: create)建立許可權,授予許可權的物件可以在資料節點下建立⼦節點;
- 資料節點(w: wirte)更新許可權,授予許可權的物件可以更新該資料節點;
- 資料節點(r: read)讀取許可權,授予許可權的物件可以讀取該節點的內容以及⼦節點的列表資訊;
- 資料節點(d: delete)刪除許可權,授予許可權的物件可以刪除該資料節點的⼦節點;
- 資料節點(a: admin)管理者許可權,授予許可權的物件可以對該資料節點體進⾏ ACL 許可權設定。
1 和 4 其實就對應zk命令
create
和delete
;
2 和 3 主要對應zk命令set
和get
;
5 主要對應zk命令setAcl
和getAcl
;
2.2 許可權模式 Scheme
接著,我們就該瞭解,到底有哪些授權的模式?而授權物件(ID)其實是和許可權模式(Scheme)對應使用的。
-
所有人可用模式(world:anyone:perm): world模式只有一個授權物件id,anyone,表示任何一個人都有許可權。
-
僅當前認證使用者可用模式(auth:user:password:perm): auth模式的授權物件是當前認證使用者。
- 提供此方案是為了方便使用者建立znode,然後將對該znode的訪問限制為僅該使用者,這是一個常見的用例;
- 如果沒有通過身份驗證的使用者,則使用身份驗證方案設定ACL將失敗;
-
口令認證模式(digest:user:password:perm): digest模式使用 username:password 字串生成MD5雜湊,然後將其用作授權物件ID。
- 這裡的 password 不是明文,而是 base64編碼(SHA1摘要演算法(明文密碼))的結果。因此和 addauth 的使用習慣不相同;
- 這裡面還有一種特殊情況,就是認證 超級管理員 的口令後,ZooKeeper客戶端可以對 ZooKeeper 上的任意資料節點進⾏任意操作;
-
IP認證模式:ip(ip:addr:perm 或者 ip:addr/bits:perm)模式使用客戶端主機ip作為授權物件ID。
- 可以針對⼀個 IP 或者⼀段 IP 地址授予某種許可權。
- ⽐如我們可以讓⼀個 IP 地址為“ip:192.168.0.110”的機器對伺服器上的某個資料節點具有寫⼊的許可權。
- 或者也可以通過“ip:192.168.0.1/24”給⼀段 IP 地址的機器賦權。
-
SSL安全認證模式:x509模式,使用安全埠時,客戶端將自動進行身份驗證,並設定x509方案的身份驗證資訊。
- 如果對這種方式感興趣,見參考文件 ZooKeeper安全認證機制:SSL 閱讀
3. 實戰
3.1 如何獲取加密的密碼?
我們已經知道了 digest認證模式需要用到 base64編碼的 SHA1密碼,那麼怎麼獲取呢?
建立一個Maven專案,加入依賴:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.9</version>
</dependency>
然後,寫一個Main程式:
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException {
// 輸出:reader:FIlPshmj74ilCpU6QOfBN00zY9w=
System.out.println(DigestAuthenticationProvider.generateDigest("reader:reader"));
// 輸出:reader:JLVf6B6eexF5jTpORnfdSP/IFVk=,但這個是錯誤的
// System.out.println(DigestAuthenticationProvider.generateDigest("reader"));
}
}
易錯點: DigestAuthenticationProvider.generateDigest
引數是 user:password
格式,而不是單純的 password
。
- 雖然,直接使用 reader 作為引數不會報錯,但是你
addauth reader:reader path
會一直驗證失敗。
3.2 setAcl授權和addauth認證
[zk: localhost:2181(CONNECTED) 0] create -e /test
Created /test
[zk: localhost:2181(CONNECTED) 1] setAcl /test digest:reader:FIlPshmj74ilCpU6QOfBN00zY9w=:r
[zk: localhost:2181(CONNECTED) 2] get /test
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /test
[zk: localhost:2181(CONNECTED) 3] addauth digest reader:reader
[zk: localhost:2181(CONNECTED) 4] get /test
null
[zk: localhost:2181(CONNECTED) 5] quit
- 首先,建立一個臨時資料結點
/test
, - 然後,設定口令認證訪問該結點,
- 在 addauth 之前,是沒有許可權讀取
/test
的資料;但是在 addauth 之後,允許讀操作, - 最後,退出當前客戶端,臨時節點
/test
會被清除。
然後,我們再看一下使用錯誤的密碼摘要的情況:
3.3 create授權和addauth認證
建立節點的同時,進行授權,這個地方有個易錯點:
[zk: localhost:2181(CONNECTED) 0] create -e /test digest:reader:FIlPshmj74ilCpU6QOfBN00zY9w=:r
Created /test
[zk: localhost:2181(CONNECTED) 1] get /test
digest:reader:FIlPshmj74ilCpU6QOfBN00zY9w=:r
[zk: localhost:2181(CONNECTED) 2] quit
你會發現,你沒有 addauth 也得到了資料,但是資料和你的acl一樣。
問題就在於,如果你想在建立節點的同時設定許可權控制,那麼你就必須初始化資料。否則,就會把acl字串當成資料儲存。
所以,我們調整一下:
[zk: localhost:2181(CONNECTED) 0] create -e /test data digest:reader:FIlPshmj74ilCpU6QOfBN00zY9w=:r
Created /test
[zk: localhost:2181(CONNECTED) 1] get /test
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /test
[zk: localhost:2181(CONNECTED) 2] addauth digest reader:reader
[zk: localhost:2181(CONNECTED) 3] get /test
data
[zk: localhost:2181(CONNECTED) 3] quit
3.4 能否給同一個結點設定多個ACL?
首先,我又準備了幾個賬號:
user:password | user:digest |
---|---|
user1:pwd1 | user1:a9l5yfb9zl8WCXjVmi5/XOC0Ep4= |
user2:pwd2 | user2:LJcj8Pt1rGm2pXKbdJDGH8+Bn+0= |
user3:pwd3 | user3:vTWpf7+XOMH/ifDkxE6KmhSUCpA= |
操作如下:
[zk: localhost:2181(CONNECTED) 0] create /user1 LiLei digest:user1:a9l5yfb9zl8WCXjVmi5/XOC0Ep4=:ra
Created /user1
[zk: localhost:2181(CONNECTED) 1] get /user1
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /user1
[zk: localhost:2181(CONNECTED) 2] addauth digest user1:pwd1
[zk: localhost:2181(CONNECTED) 3] get /user1
LiLei
[zk: localhost:2181(CONNECTED) 4] getAcl /user1
'digest,'user1:a9l5yfb9zl8WCXjVmi5/XOC0Ep4=
: ra
[zk: localhost:2181(CONNECTED) 5] setAcl /user1 digest:user2:LJcj8Pt1rGm2pXKbdJDGH8+Bn+0=:rw
[zk: localhost:2181(CONNECTED) 6] getAcl /user1
Authentication is not valid : /user1
[zk: localhost:2181(CONNECTED) 7] addauth digest user2:pwd2
[zk: localhost:2181(CONNECTED) 8] getAcl /user1
'digest,'user2:x
: rw
[zk: localhost:2181(CONNECTED) 9] quit
- 首先,建立資料結點
/user1
,並且授權口令user1:pwd1
允許讀取和管理許可權; - 接著,使用
user1:pwd1
完成 addauth 授權認證,並讀取到了/user1
對應的資料和許可權資訊; - 然後,修改了 ACL,原先的
user1:pwd1
口令失效了; - 重新使用
user2:pwd2
完成 addauth 授權認證,再次讀取許可權資訊,此時發現新的許可權資訊覆蓋了原來的許可權資訊;
綜上所述,同一個znode不支援多個 ACL。
3.5 多次addauth可以獲取許可權合集?
實驗如下:
[zk: localhost:2181(CONNECTED) 0] create /user2 Lisa digest:user2:LJcj8Pt1rGm2pXKbdJDGH8+Bn+0=:ra
Created /user2
[zk: localhost:2181(CONNECTED) 1] create /user3 Simon digest:user3:vTWpf7+XOMH/ifDkxE6KmhSUCpA=:ra
Created /user3
[zk: localhost:2181(CONNECTED) 2] addauth digest user2:pwd2
[zk: localhost:2181(CONNECTED) 3] get /user2
Lisa
[zk: localhost:2181(CONNECTED) 4] get /user3
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /user3
[zk: localhost:2181(CONNECTED) 5] addauth digest user3:pwd3
[zk: localhost:2181(CONNECTED) 7] get /user2
Lisa
[zk: localhost:2181(CONNECTED) 8] get /user3
Simon
[zk: localhost:2181(CONNECTED) 9] quit
由此可見,addauth 會取當前客戶端認證後獲取的許可權合集。
3.6 許可權受限怎麼辦?
- 第一個方法是禁用 ACL 許可權控制;
- 第二個方法是超級管理員模式。
本文主要說的是 Docker 容器執行的 ZooKeeper 如何處理?
3.6.1 禁用 ACL 許可權控制
★ 可以通過配置檔案zoo.cfg中新增skipACL=yes進⾏配置,預設是no,可以配置為true, 則配置過的 ACL 將不再進⾏許可權檢測:
首先,用 docker images
檢視下載的映象:
如圖所示,30993cacc7c9
就是 zookeeper:3.5.9
的 映象ID。
# 簡單解釋一下引數:
# --name是給啟動的容器取的名字,以後啟動容器可以使用這個名字來啟動
# -p 宿主主機埠:容器埠, 2181 是 zookeeper 的預設埠號, 因為宿主機已經有其他zookeeper容器佔用了2181,所以此處改為2281
# --restart always 表示容器如果關閉退出就是重啟
# -d 表示容器以後臺守護程序啟動
# -v 宿主機檔案路徑:容器檔案路徑
# 末尾的 30993cacc7c9 表示映象ID
docker run --name zookeeper-1 -p 2281:2181 --restart always -d -v D:\DockerContainer\zookeeper\zoo.cfg:/conf/zoo.cfg 30993cacc7c9
然後 D:\DockerContainer\zookeeper\zoo.cfg
檔案內容為:
skipACL=yes
dataDir=/data
dataLogDir=/datalog
tickTime=2000
initLimit=5
syncLimit=2
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
admin.enableServer=true
server.1=localhost:2888:3888;2181
接著,登入容器 docker exec -it zookeeper-1 bash
,啟動zk客戶端:
然後,做操作都不需要許可權了:
[zk: localhost:2181(CONNECTED) 0] create /test data digest:user1:a9l5yfb9zl8WCXjVmi5/XOC0Ep4=:w
Created /test
[zk: localhost:2181(CONNECTED) 1] get /test
data
[zk: localhost:2181(CONNECTED) 2] delete /test
★ 可以通過設定額外配置引數skipACL=yes進⾏配置,預設是no,可以配置為true, 則配置過的ACL將不再進⾏許可權檢測
docker run --name=zookeeper-2 -p 2381:2181 --restart always -d -e ZOO_CFG_EXTRA="skipACL=yes" 30993cacc7c9
★ 可以通過新增JVM引數-Dzookeeper.skipACL=yes
進⾏配置,預設是no,可以配置為true, 則配置過的ACL將不再進⾏許可權檢測
docker run --name=zookeeper-3 -p 2481:2181 --restart always -d -e JVMFLAGS="-Dzookeeper.skipACL=yes" 30993cacc7c9
3.6.2 超級管理員super
設定zk啟動時的JVM引數為 -Dzookeeper.DigestAuthenticationProvider.superDigest=super1:WqkSAJNIl+iMSE0y/0xAI3lPT5o=
指定超管賬號口令為 super1:admin
。
docker run --name=zookeeper-4 -p 2581:2181 --restart always -d -e JVMFLAGS="-Dzookeeper.DigestAuthenticationProvider.superDigest=super1:WqkSAJNIl+iMSE0y/0xAI3lPT5o=" 30993cacc7c9
接著,登入容器並啟動zk客戶端:
以下實驗部分:
[zk: localhost:2181(CONNECTED) 0] create /test data digest:user1:a9l5yfb9zl8WCXjVmi5/XOC0Ep4=:w
Created /test
[zk: localhost:2181(CONNECTED) 1] get /test
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /test
[zk: localhost:2181(CONNECTED) 2] addauth digest super1:admin
[zk: localhost:2181(CONNECTED) 3] get /test
data
[zk: localhost:2181(CONNECTED) 4] quit
- 我們允許使用者 user1 對路徑為
/test
的節點進行資料的修改; - 我們獲取資料時,提示沒有許可權;
- 此時,賦予當前客戶端超級管理員許可權;
- 超級管理員的所有操作都會跳過許可權檢查。
簡單的客戶端程式碼:
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Watcher connectedWatcher = event -> {
if (Watcher.Event.KeeperState.SyncConnected.equals(event.getState())
&& Watcher.Event.EventType.None.equals(event.getType())
&& event.getPath() == null) {
System.out.println("========= ZooKeeper connected ==========");
latch.countDown();
}
};
try (ZooKeeper zk = new ZooKeeper("localhost:2581", 30, connectedWatcher)) {
latch.await();
try {
byte[] data = zk.getData("/test", null, null);
Optional.ofNullable(data).map(String::new).ifPresent(value -> System.out.println("Node /test data: " + value));
} catch (KeeperException e) {
System.out.println("Something wrong:" + e.getMessage());
}
zk.addAuthInfo("digest", "super1:admin".getBytes());
System.out.println("========= after addauth super ==========");
try {
byte[] data = zk.getData("/test", null, null);
Optional.ofNullable(data).map(String::new).ifPresent(value -> System.out.println("Node /test data: " + value));
} catch (KeeperException e) {
System.out.println("Something wrong:" + e.getMessage());
}
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
執行結果:
========= ZooKeeper connected ==========
Something wrong:KeeperErrorCode = NoAuth for /test
========= after addauth super ==========
Node /test data: data
參考文件
ZooKeeper ACLPermissions 閱讀
ZooKeeper安全認證機制:SSL 閱讀
Docker ZooKeeper 官方文件 閱讀
docker windows下掛載目錄和檔案 閱讀
Zookeeper Acl許可權 超級使用者許可權 怎麼跳過ACL密碼/賬戶驗證 閱讀