爲了不存儲在 Zookeeper 上的數據被其餘程序或者人爲誤修改,Zookeeper 提供了 ACL(Access Control Lists) 進行權限控制。只有擁有對應權限的用戶才能夠對節點進行增刪改查等操做。下文分別介紹使用原生的 Shell 命令和 Apache Curator 客戶端進行權限設置。java
想要給某個節點設置權限 (ACL),有如下兩個可選的命令:node
# 1.給已有節點賦予權限 setAcl path acl # 2.在建立節點時候指定權限 create [-s] [-e] path data acl
查看指定節點的權限命令以下:git
getAcl path
Zookeeper 的權限由[scheme : id :permissions]三部分組成,其中 Schemes 和 Permissions 內置的可選項分別以下:github
Permissions 可選項:shell
Schemes 可選項:apache
world:anyone:[permissons]
;auth:user:password:[permissons]
,使用這種模式時,你須要先進行登陸,以後採用 auth 模式設置權限時,user
和 password
都將使用登陸的用戶名和密碼;auth:user:BASE64(SHA1(password)):[permissons]
,這種形式下的密碼必須經過 SHA1 和 BASE64 進行雙重加密;ip:182.168.0.168:[permissions]
;能夠使用以下所示的命令爲當前 Session 添加用戶認證信息,等價於登陸操做。session
# 格式 addauth scheme auth #示例:添加用戶名爲heibai,密碼爲root的用戶認證信息 addauth digest heibai:root
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 # 權限不足
[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
[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
限定只有特定的 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
模式。
須要修改啓動腳本 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
這裏以 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>
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 開源項目: 大數據入門指南