1. 程式人生 > >ZooKeeper系列(五)—— ACL 許可權控制

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 模式設定許可權時,userpassword 都將使用登入的使用者名稱和密碼;
  • 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 開源專案: 大資料入門指南