ZooKeeper系列(五)—— ACL 權限控制

1、前言

爲了不存儲在 Zookeeper 上的數據被其餘程序或者人爲誤修改,Zookeeper 提供了 ACL(Access Control Lists) 進行權限控制。只有擁有對應權限的用戶才能夠對節點進行增刪改查等操做。下文分別介紹使用原生的 Shell 命令和 Apache Curator 客戶端進行權限設置。java

2、使用Shell進行權限管理

2.1 設置與查看權限

想要給某個節點設置權限 (ACL),有如下兩個可選的命令:node

# 1.給已有節點賦予權限
 setAcl path acl
 
 # 2.在建立節點時候指定權限
 create [-s] [-e] path data acl

查看指定節點的權限命令以下:git

getAcl path

2.2 權限組成

Zookeeper 的權限由[scheme : id :permissions]三部分組成,其中 Schemes 和 Permissions 內置的可選項分別以下:github

Permissions 可選項shell

  • CREATE:容許建立子節點;
  • READ:容許從節點獲取數據並列出其子節點;
  • WRITE:容許爲節點設置數據;
  • DELETE:容許刪除子節點;
  • ADMIN:容許爲節點設置權限。

Schemes 可選項apache

  • world:默認模式,全部客戶端都擁有指定的權限。world 下只有一個 id 選項,就是 anyone,一般組合寫法爲 world:anyone:[permissons]
  • auth:只有通過認證的用戶才擁有指定的權限。一般組合寫法爲 auth:user:password:[permissons],使用這種模式時,你須要先進行登陸,以後採用 auth 模式設置權限時,userpassword 都將使用登陸的用戶名和密碼;
  • digest:只有通過認證的用戶才擁有指定的權限。一般組合寫法爲 auth:user:BASE64(SHA1(password)):[permissons],這種形式下的密碼必須經過 SHA1 和 BASE64 進行雙重加密;
  • ip:限制只有特定 IP 的客戶端才擁有指定的權限。一般組成寫法爲 ip:182.168.0.168:[permissions]
  • super:表明超級管理員,擁有全部的權限,須要修改 Zookeeper 啓動腳本進行配置。

2.3 添加認證信息

能夠使用以下所示的命令爲當前 Session 添加用戶認證信息,等價於登陸操做。session

# 格式
addauth scheme auth 

#示例:添加用戶名爲heibai,密碼爲root的用戶認證信息
addauth digest heibai:root

2.4 權限設置示例

1. world模式

world 是一種默認的模式,即建立時若是不指定權限,則默認的權限就是 world。ide

[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 模式就能夠避免這種麻煩。oop

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

3、使用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 開源項目大數據入門指南

相關文章
相關標籤/搜索