Zookeeper ACL(访问控制列表)

什么是 ACL?

Zookeeper 采用 ACL (Access Control Lists) 策略来进行权限控制,类似于 UNIX 文件系统的权限控制,目的为了保障数据安全性。

Zookeeper 的 ACL 分为三个维度:scheme(权限策略)、id(用户)、permission(权限)。

通常表示为:scheme:id:permission 来构成权限列表,其中:

  • scheme:代表采用某种权限机制

  • id:代表允许访问的用户

  • permissions:代表权限(组合字符串)

scheme 权限策略

 策略名    描述
worldworld 下只有一个 id,即只有一个用户,也就是 anyone,那么组合的写法就是:

world:anyone:[permissions]。

world:anyone 代表任何人,zookeeper 中对所有人有权限的节点就是属于 world:anyone 的。

auth代表认证登录,需要注册用户有权限就可以,使用的是明文密码,形式为:

auth:user:password:[permissions]

它不需要 id, 只要是通过 authentication 的 user 都有权限(zookeeper 支持通过 kerberos 来进行 authencation,也支持 username/password 形式的authentication)。

digest需要对密码加密才能访问,使用的是加密密码,组合形式为 digest:

username:BASE64(SHA1(username:password)):[permissions]。

ip它对应的 id 为客户机的 IP 地址,设置的时候可以设置一个 ip 段,此时限制 ip 进行访问。比如 ip:192.168.1.1:[permissions]
super代表超级管理员,拥有所有的权限

id 用户

id 是验证模式,不同的 scheme,id 的值也不一样。默认为 anyone。

用户策略名ID 验证模式描述
authusername:password
digestusername:BASE64(SHA1(username:password))
ip客户端的 ip 地址
worldanyone

permission 权限

Zookeeper 定义了五种权限:

权限名权限描述
CREATE(简称:c)创建子节点的权限。允许创建子节点;
DELETE(简称:d)删除节点的权限。允许删除子节点;
READ(简称:r)读取节点数据的权限。允许从节点获取数据并列出其子节点;
WRITE(简称:w)修改节点数据的权限。允许为节点设置数据;
ADMIN(简称:a)设置子节点权限的权限,允许为节点设置权限。

ACL 相关命令

在 ZooKeeper 中,可以通过如下命令操作 ACL:

setAcl 命令

setAcl 命令用于在 ZooKeeper 中设置一个节点的 Acl 权限。语法如下:

setAcl [-s] [-v version] [-R] path acl

参数说明:

  • -s 选项表示以递归方式设置指定节点及其子节点的 ACL。如果不使用 -s 选项,则只设置指定节点的 ACL。

  • -v version 选项用于指定 ACL 的版本号。只有当指定节点的 ACL 版本号与提供的版本号匹配时,ACL 才会被设置。如果不指定版本号,则不会进行版本号检查。

  • -R 选项表示递归设置 ACL,即设置指定节点及其子节点的 ACL。

  • path 是要设置 ACL 的节点路径。

  • acl 是要设置的 ACL 定义,包括权限和身份验证信息。

示例:

(1)设置指定节点的 Acl,如下:

[zkshell: 28] addauth digest user1:12345
[zkshell: 30] setAcl /acl_auth_test auth:user1:12345:crwad
[zkshell: 31] getAcl /acl_auth_test
	'digest,'user1:+owfoSBn/am19roBPzR1/MfCblE=
	: cdrwa

(2)使用 -R 选项以递归方式设置 Acl,如下:

[zkshell: 32] ls /acl_auth_test
	[child_1, child_2]
[zkshell: 33] getAcl /acl_auth_test/child_2
	'world,'anyone
	: cdrwa
[zkshell: 34] setAcl -R /acl_auth_test auth:user1:12345:crwad
[zkshell: 35] getAcl /acl_auth_test/child_2
	'digest,'user1:+owfoSBn/am19roBPzR1/MfCblE=
	: cdrwa

(3)使用 -v 选项设置 Acl 的 Acl 版本,我们可以从 aclVersion 中找到。例如:

[zkshell: 36] stat /acl_auth_test
	cZxid = 0xf9fc0000001c
	ctime = Tue Mar 26 16:50:58 CST 2019
	mZxid = 0xf9fc0000001c
	mtime = Tue Mar 26 16:50:58 CST 2019
	pZxid = 0xf9fc0000001f
	cversion = 2
	dataVersion = 0
	aclVersion = 3
	ephemeralOwner = 0x0
	dataLength = 0
	numChildren = 2

[zkshell: 37] setAcl -v 3 /acl_auth_test auth:user1:12345:crwad

getAcl 命令

getAcl 命令用于在 ZooKeeper 中获取指定节点的访问控制列表(ACL)。ACL 定义了对节点的访问权限,包括读取、写入、创建子节点等操作的权限。语法如下:

getAcl [-s] path

参数说明:

  • -s  可选参数,表示以静态方式获取ACL信息。如果不加该参数,则表示获取动态ACL信息。

  • path  是要获取 ACL 的节点路径。

示例:

(1)查看 /brokers 节点的 ACL 权限,如下:

# 查看节点的 ACL 信息
# 该节点采用的 world 策略,允许任何登录到当前 Zookeeper 的客户端访问
[zk: localhost:2181(CONNECTED) 25] getAcl /brokers
'world,'anyone
: cdrwa

# 已静态的方式获取 ACL 信息
[zk: localhost:2181(CONNECTED) 3] getAcl -s /brokers
'world,'anyone
: cdrwa
cZxid = 0x59
ctime = Mon Dec 18 21:50:48 CST 2023
mZxid = 0x59
mtime = Mon Dec 18 21:50:48 CST 2023
pZxid = 0x59
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

addauth 命令

addAuth 命令用于向 ZooKeeper 服务器添加认证信息。语法如下:

addauth scheme auth

参数说明:

  • scheme:表示认证方案,例如 digest、sasl 等

  • auth:表示认证信息,具体格式根据认证方案而定,如方案为 digest,则 auth 为 “username:password”

示例:

(1)向 zookeeper 服务器添加认证信息,如下:

# 查看 /acl_digest_test 节点的 ACL 权限信息
# 查看失败,提示权限不足
[zkshell: 9] getAcl /acl_digest_test
    Insufficient permission : /acl_digest_test
    
# 使用 addauth 命令添加权限,相当于使用常见的登录
[zkshell: 10] addauth digest user1:12345

# 再次获取 /acl_digest_test 节点的 ACL 权限信息,成功了
[zkshell: 11] getAcl /acl_digest_test
    'digest,'user1:+owfoSBn/am19roBPzR1/MfCblE=
    : cdrwa

# 添加一个超级用户
# Notice:set zookeeper.DigestAuthenticationProvider
# e.g. zookeeper.DigestAuthenticationProvider.superDigest=zookeeper:qW/HnTfCSoQpB5G8LgkwT3IbiFc=
[zkshell: 12] addauth digest zookeeper:admin

权限示例

查看节点 ACL

# 创建 /node1 节点
[zk: localhost:2181(CONNECTED) 0] create /node1 myData
Created /node1

# 获取 /node1 节点的 ACL 信息
[zk: localhost:2181(CONNECTED) 1] getAcl /node1
'world,'anyone
: cdrwa

注意:ZooKeeper 创建节点时的默认 ACL 为“'world,'anyone: cdrwa”,表示任何连接到 Zookeeper 的客户端都能对该节点进行 cdrwa 操作。

world 权限模式示例

world 权限模式只有一种设置模式。就是 setAcl world:anyone:[r][w][c][d][a],例如:

# 设置 /node1 节点的权限,不允许读取
[zk: localhost:2181(CONNECTED) 2] setAcl /node1 world:anyone:wcda

# 获取 /node1 节点的 ACL 信息
[zk: localhost:2181(CONNECTED) 3] getAcl /node1
'world,'anyone
: cdwa

# 尝试获取 /node1 节点的内容
[zk: localhost:2181(CONNECTED) 4] get /node1
Insufficient permission : /node1

上面输出信息提示“Insufficient permission”权限不足,不能读取 /node1 节点的内容。

IP 权限模式示例

该模式使用的 ACL 方式是 ip:192.168.10.127:[a][d][c][w][r],例如:

# 创建 /ip_node 节点
[zk: localhost:2181(CONNECTED) 5] create /ip_node 123456
Created /ip_node

# 设置节点权限
[zk: localhost:2181(CONNECTED) 6] setAcl /ip_node ip:192.168.1.200:adcwr

上述示例中,设置了只有 ip 为 192.168.1.200 的客户端连接才能进行 adcwr 操作,其他 ip 啥操作都做不了。因为上例中设置 ACL 的客户端不是这个 ip,所以设置了后,他就失去对该节点的权限了,所以 getAcl 命令会没有权限。如下:

# 获取 /ip_node 节点的 ACL 信息,显示没有权限
[zk: localhost:2181(CONNECTED) 7] getAcl /ip_node
Insufficient permission : /ip_node

auth 授权模式示例

注意,这种模式需要配合 addauth 命令,addauth 命令用来添加认证用户,类似于登录操作。使用 auth 授权模式的步骤如下:

(1)先添加授权用户 addauth digest username:password,其中 username 为用户名,password 为登录密码(明文)。ZooKeeper 客户端会自动对密码加密,例如:

# 在当前客户端回话中添加用户名为 root,密码为 123456 的授权用户
[zk: localhost:2181(CONNECTED) 3] addauth digest root:123456

(2)给节点设置权限,只有登录了该授权用户的客户端连接才能进行操作,例如:

# 创建 /auth_node 节点
[zk: localhost:2181(CONNECTED) 4] create /auth_node myData
Created /auth_node

# 设置 /auth_node 节点的 ACL 权限
[zk: localhost:2181(CONNECTED) 5] setAcl /auth_node auth:root:cdwra

# 获取 /auth_node 节点的 ACL 内容,成功了
# 这是因为当前回话已经添加了授权用户
[zk: localhost:2181(CONNECTED) 6] getAcl /auth_node
'digest,'root:u53OoA8hprX59uwFsvQBS3QuI00=
: cdrwa

# 获取 /auth_node 节点的内容
[zk: localhost:2181(CONNECTED) 7] get /auth_node
myData

(3)如果执行 quit 命令退出当前客户端,重新打开 zkcli 客户端,重新连接到 ZooKeeper,例如:

# 获取 /auth_node 节点内容失败,这是因为当前回话是重新登录的新回话
# 还没有添加授权用户
[zk: localhost:2181(CONNECTED) 0] get /auth_node
Insufficient permission : /auth_node

# 手动添加授权用户,用户为 root,密码为 123456
[zk: localhost:2181(CONNECTED) 1] addauth digest root:123456

# 再次获取 /auth_node 节点的内容和 ACL 信息
[zk: localhost:2181(CONNECTED) 2] get /auth_node
myData
[zk: localhost:2181(CONNECTED) 3] getAcl /auth_node
'digest,'root:u53OoA8hprX59uwFsvQBS3QuI00=
: cdrwa

digest 授权模式示例

digest 授权模式基于账号密码的授权模式,与 auth 模式类似,只是他设置权限之前不用使用 addauth 命令添加权限用户。而是,直接使用命令 setAcl path digest:username:password:acl 进行授权就行。

注意:这里的密码要使用加密后的密码(加密方式:BASE64(SHA1(username:password)) ),不能使用明文密码。

(1)生成加密后的密码,下面提供两种方式生成密码:

第一种:使用 Linux 命令进行生成,如下:

echo -n username:password | openssl dgst -binary -sha1 | openssl base64

注意:需要安装 openssl 库,上面的“password”就是你的明文密码。

第二种:采用编程语言生成,下面使用 Java 生成密码,如下:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @author 
 * @since 1.0.0  2023/12/18 16:30
 **/
public class Demo20231218163009 

    public static void main(String[] args) {
        // 用户名:密码
        String input = "admin:123456";
        try {
            // 获取 SHA-1 的 MessageDigest 实例
            MessageDigest sha256Digest = MessageDigest.getInstance("SHA-1");
            // 计算哈希值
            byte[] shaBytes = sha256Digest.digest(input.getBytes());
            // 使用 Base64 格式输出加密信息
            String pass = Base64.getEncoder().encodeToString(shaBytes);
            System.out.println(pass);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

运行示例,输出如下:

0uek/hZ/V9fgiM35b0Z2226acMQ=

(2)验证 digest 授权模式,如下:

# 创建 /digest_node 节点
[zk: localhost:2181(CONNECTED) 23] create /digest_node myData
Created /digest_node

# 给 /digest_node 节点设置 ACL 权限,注意:0uek/hZ/V9fgiM35b0Z2226acMQ= 就是我们生成的加密字符串
[zk: localhost:2181(CONNECTED) 24] setAcl /digest_node digest:admin:0uek/hZ/V9fgiM35b0Z2226acMQ=:crwda

# 试着没有权限认证,获取 /digest_node 节点的内容
# 出错了,权限不够
[zk: localhost:2181(CONNECTED) 25] get /digest_node
Insufficient permission : /digest_node

# 使用 addauth 命令添加授权用户,相当于登录操作
[zk: localhost:2181(CONNECTED) 26] addauth digest admin:123456

# 再次尝试获取 /digest_node 节点的内容,成功了
[zk: localhost:2181(CONNECTED) 27] get /digest_node
myData

注意了,节点可以设置多个 ACL 权限,ACL 之间采用逗号隔开,例如:

# 创建 /multi_auth_node 节点
[zk: localhost:2181(CONNECTED) 4] create /multi_auth_node myData
Created /multi_auth_node

# 给 /multi_auth_node 节点添加 auth 和 world 类型的授权模式
[zk: localhost:2181(CONNECTED) 5] setAcl /multi_auth_node auth:admin:cdwra,world:anyone:cdr

# 查看 /multi_auth_node 节点的 ACL 信息
[zk: localhost:2181(CONNECTED) 6] getAcl /multi_auth_node
'digest,'root:u53OoA8hprX59uwFsvQBS3QuI00=
: cdrwa
'world,'anyone
: cdr

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号