Zookeeper 采用 ACL (Access Control Lists) 策略来进行权限控制,类似于 UNIX 文件系统的权限控制,目的为了保障数据安全性。
Zookeeper 的 ACL 分为三个维度:scheme(权限策略)、id(用户)、permission(权限)。
通常表示为:scheme:id:permission 来构成权限列表,其中:
scheme:代表采用某种权限机制
id:代表允许访问的用户
permissions:代表权限(组合字符串)
策略名 | 描述 |
---|---|
world | world 下只有一个 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 是验证模式,不同的 scheme,id 的值也不一样。默认为 anyone。
用户策略名 | ID 验证模式描述 |
---|---|
auth | username:password |
digest | username:BASE64(SHA1(username:password)) |
ip | 客户端的 ip 地址 |
world | anyone |
Zookeeper 定义了五种权限:
权限名 | 权限描述 |
---|---|
CREATE(简称:c) | 创建子节点的权限。允许创建子节点; |
DELETE(简称:d) | 删除节点的权限。允许删除子节点; |
READ(简称:r) | 读取节点数据的权限。允许从节点获取数据并列出其子节点; |
WRITE(简称:w) | 修改节点数据的权限。允许为节点设置数据; |
ADMIN(简称:a) | 设置子节点权限的权限,允许为节点设置权限。 |
在 ZooKeeper 中,可以通过如下命令操作 ACL:
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 命令用于在 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 命令用于向 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
# 创建 /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 权限模式只有一种设置模式。就是 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 节点的内容。
该模式使用的 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
注意,这种模式需要配合 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 授权模式基于账号密码的授权模式,与 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