ZooKeeper系列(五)—— ACL 許可權控制
一、前言
為了避免儲存在 Zookeeper 上的資料被其他程式或者人為誤修改,Zookeeper 提供了 ACL(Access Control Lists) 進行許可權控制。只有擁有對應許可權的使用者才可以對節點進行增刪改查等操作。下文分別介紹使用原生的 Shell 命令和 Apache Curator 客戶端進行許可權設定。
二、使用Shell進行許可權管理
2.1 設定與檢視許可權
想要給某個節點設定許可權 (ACL),有以下兩個可選的命令:
# 1.給已有節點賦予許可權 setAcl path acl # 2.在建立節點時候指定許可權 create [-s] [-e] path data acl
檢視指定節點的許可權命令如下:
getAcl path
2.2 許可權組成
Zookeeper 的許可權由[scheme : id :permissions]三部分組成,其中 Schemes 和 Permissions 內建的可選項分別如下:
Permissions 可選項:
- CREATE:允許建立子節點;
- READ:允許從節點獲取資料並列出其子節點;
- WRITE:允許為節點設定資料;
- DELETE:允許刪除子節點;
- ADMIN:允許為節點設定許可權。
Schemes 可選項:
- world:預設模式,所有客戶端都擁有指定的許可權。world 下只有一個 id 選項,就是 anyone,通常組合寫法為
world:anyone:[permissons]
- auth:只有經過認證的使用者才擁有指定的許可權。通常組合寫法為
auth:user:password:[permissons]
,使用這種模式時,你需要先進行登入,之後採用 auth 模式設定許可權時,user
和password
都將使用登入的使用者名稱和密碼; - digest:只有經過認證的使用者才擁有指定的許可權。通常組合寫法為
auth:user:BASE64(SHA1(password)):[permissons]
,這種形式下的密碼必須通過 SHA1 和 BASE64 進行雙重加密; - ip:限制只有特定 IP 的客戶端才擁有指定的許可權。通常組成寫法為
ip:182.168.0.168:[permissions]
- super:代表超級管理員,擁有所有的許可權,需要修改 Zookeeper 啟動指令碼進行配置。
2.3 新增認證資訊
可以使用如下所示的命令為當前 Session 新增使用者認證資訊,等價於登入操作。
# 格式
addauth scheme auth
#示例:新增使用者名稱為heibai,密碼為root的使用者認證資訊
addauth digest heibai:root
2.4 許可權設定示例
1. world模式
world 是一種預設的模式,即建立時如果不指定許可權,則預設的許可權就是 world。
[zk: localhost:2181(CONNECTED) 32] create /hadoop 123
Created /hadoop
[zk: localhost:2181(CONNECTED) 33] getAcl /hadoop
'world,'anyone #預設的許可權
: cdrwa
[zk: localhost:2181(CONNECTED) 34] setAcl /hadoop world:anyone:cwda # 修改節點,不允許所有客戶端讀
....
[zk: localhost:2181(CONNECTED) 35] get /hadoop
Authentication is not valid : /hadoop # 許可權不足
2. auth模式
[zk: localhost:2181(CONNECTED) 36] addauth digest heibai:heibai # 登入
[zk: localhost:2181(CONNECTED) 37] setAcl /hadoop auth::cdrwa # 設定許可權
[zk: localhost:2181(CONNECTED) 38] getAcl /hadoop # 獲取許可權
'digest,'heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s= #使用者名稱和密碼 (密碼經過加密處理),注意返回的許可權型別是 digest
: cdrwa
#使用者名稱和密碼都是使用登入的使用者名稱和密碼,即使你在建立許可權時候進行指定也是無效的
[zk: localhost:2181(CONNECTED) 39] setAcl /hadoop auth:root:root:cdrwa #指定使用者名稱和密碼為 root
[zk: localhost:2181(CONNECTED) 40] getAcl /hadoop
'digest,'heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s= #無效,使用的使用者名稱和密碼依然還是 heibai
: cdrwa
3. digest模式
[zk:44] create /spark "spark" digest:heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s=:cdrwa #指定使用者名稱和加密後的密碼
[zk:45] getAcl /spark #獲取許可權
'digest,'heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s= # 返回的許可權型別是 digest
: cdrwa
到這裡你可以發現使用 auth
模式設定的許可權和使用 digest
模式設定的許可權,在最終結果上,得到的許可權模式都是 digest
。某種程度上,你可以把 auth
模式理解成是 digest
模式的一種簡便實現。因為在 digest
模式下,每次設定都需要書寫使用者名稱和加密後的密碼,這是比較繁瑣的,採用 auth
模式就可以避免這種麻煩。
4. ip模式
限定只有特定的 ip 才能訪問。
[zk: localhost:2181(CONNECTED) 46] create /hive "hive" ip:192.168.0.108:cdrwa
[zk: localhost:2181(CONNECTED) 47] get /hive
Authentication is not valid : /hive # 當前主機已經不能訪問
這裡可以看到當前主機已經不能訪問,想要能夠再次訪問,可以使用對應 IP 的客戶端,或使用下面介紹的 super
模式。
5. super模式
需要修改啟動指令碼 zkServer.sh
,並在指定位置新增超級管理員賬戶和密碼資訊:
"-Dzookeeper.DigestAuthenticationProvider.superDigest=heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s="
修改完成後需要使用 zkServer.sh restart
重啟服務,此時再次訪問限制 IP 的節點:
[zk: localhost:2181(CONNECTED) 0] get /hive #訪問受限
Authentication is not valid : /hive
[zk: localhost:2181(CONNECTED) 1] addauth digest heibai:heibai # 登入 (新增認證資訊)
[zk: localhost:2181(CONNECTED) 2] get /hive #成功訪問
hive
cZxid = 0x158
ctime = Sat May 25 09:11:29 CST 2019
mZxid = 0x158
mtime = Sat May 25 09:11:29 CST 2019
pZxid = 0x158
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
三、使用Java客戶端進行許可權管理
3.1 主要依賴
這裡以 Apache Curator 為例,使用前需要匯入相關依賴,完整依賴如下:
<dependencies>
<!--Apache Curator 相關依賴-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
<!--單元測試相關依賴-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
3.2 許可權管理API
Apache Curator 許可權設定的示例如下:
public class AclOperation {
private CuratorFramework client = null;
private static final String zkServerPath = "192.168.0.226:2181";
private static final String nodePath = "/hadoop/hdfs";
@Before
public void prepare() {
RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
client = CuratorFrameworkFactory.builder()
.authorization("digest", "heibai:123456".getBytes()) //等價於 addauth 命令
.connectString(zkServerPath)
.sessionTimeoutMs(10000).retryPolicy(retryPolicy)
.namespace("workspace").build();
client.start();
}
/**
* 新建節點並賦予許可權
*/
@Test
public void createNodesWithAcl() throws Exception {
List<ACL> aclList = new ArrayList<>();
// 對密碼進行加密
String digest1 = DigestAuthenticationProvider.generateDigest("heibai:123456");
String digest2 = DigestAuthenticationProvider.generateDigest("ying:123456");
Id user01 = new Id("digest", digest1);
Id user02 = new Id("digest", digest2);
// 指定所有許可權
aclList.add(new ACL(Perms.ALL, user01));
// 如果想要指定許可權的組合,中間需要使用 | ,這裡的|代表的是位運算中的 按位或
aclList.add(new ACL(Perms.DELETE | Perms.CREATE, user02));
// 建立節點
byte[] data = "abc".getBytes();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(aclList, true)
.forPath(nodePath, data);
}
/**
* 給已有節點設定許可權,注意這會刪除所有原來節點上已有的許可權設定
*/
@Test
public void SetAcl() throws Exception {
String digest = DigestAuthenticationProvider.generateDigest("admin:admin");
Id user = new Id("digest", digest);
client.setACL()
.withACL(Collections.singletonList(new ACL(Perms.READ | Perms.DELETE, user)))
.forPath(nodePath);
}
/**
* 獲取許可權
*/
@Test
public void getAcl() throws Exception {
List<ACL> aclList = client.getACL().forPath(nodePath);
ACL acl = aclList.get(0);
System.out.println(acl.getId().getId()
+ "是否有刪讀許可權:" + (acl.getPerms() == (Perms.READ | Perms.DELETE)));
}
@After
public void destroy() {
if (client != null) {
client.close();
}
}
}
完整原始碼見本倉庫: https://github.com/heibaiying/BigData-Notes/tree/master/code/Zookeeper/curator
更多大資料系列文章可以參見 GitHub 開源專案: 大資料入門指南