天天看点

【zookeeper】zookeeper基础知识 《ACL》

文章目录

    • 1. 概述
      • 1.1 scheme
      • 1.2 授权对象id
      • 1.3 permission
    • 2. ACL相关命令
    • 3. 测试
      • 3.1 schema=Digest例子
        • 3.1.1 代码生成ID
        • 3.1.2 xshell生成ID
        • 3.1.3 总结
      • 3.3 schema=Auth 明文授权
      • 3.3 schema=IP
      • 3.4 schema=world

Access Control在分布式系统中重要性是毋庸置疑的,今天这篇文章来介绍一下Zookeeper中的Access Control(ACL)。

1. 概述

传统的文件系统中,ACL分为两个维度,一个是属组,一个是权限,子目录/文件默认继承父目录的ACL。

Zookeeper 的ACL 权限控制,可以控制节点的读写操作,保证数据的安全性。在Zookeeper中,node的ACL是没有继承关系的,是独立控制的。Zookeeper的ACL,可以从三个维度来理解:一是

scheme

; 二是

user

; 三是

permission

,通常表示为

scheme:id:permissions

【zookeeper】zookeeper基础知识 《ACL》

使用zkCli时,ACL的格式由::三段组成。

  • schema:可以取下列值:world, auth, digest, host/ip
  • id: 标识身份,值依赖于schema做解析。
  • acl:就是权限:cdwra分别表示create, delete,write,read, admin
注意:id受scheme影响,要和其保持一致;permission是独立的;通过冒号来分割三个参数

其特性如下:

  • ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限
  • 每个znode支持设置多种权限控制方案和多个权限
  • 子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点

1.1 scheme

scheme对应于采用哪种方案来进行权限管理,zookeeper实现了一个pluggable的ACL方案,可以通过扩展scheme,来扩展ACL的机制。zookeeper-3.4.4缺省支持下面几种scheme:

  • world

    :

    它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的

  • auth

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

    :

    即用户名:密码这种方式认证,这也是业务系统中最常用的。

    username:password

    字符串来产生一个

    MD5

    串,然后该串被用来作为ACL ID。ID表达式为

    username:base64

    ,base64是password的SHA1摘要的编码。

    例,假如username=user ,password=123456,那么完整的ACL为:

    digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa
    
    "digest"对应scheme
    "user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo"=对应 授权对象id,"6DY5WhzOfGsWQ1XFuIyzxkpwdPo="为username:123456经base64转化的
    "cdrwa"对应permissions
               
  • ip

    :

    它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段

  • super

    :

    在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)

1.2 授权对象id

id与scheme是紧密相关的,具体的情况在上面介绍scheme的过程都已介绍,这里不再赘述。

1.3 permission

zookeeper目前支持下面一些权限:

  • CREATE(c)

    创建权限,可以在在当前node下创建child node
  • DELETE(d)

    删除权限,可以删除当前的node
  • READ(r)

    读权限,可以获取当前node的数据,可以list当前node所有的child nodes
  • WRITE(w)

    写权限,可以向当前node写数据
  • ADMIN(a)

    管理权限,可以设置当前node的permission

2. ACL相关命令

getAcl:获取某个节点的acl权限信息

setAcl:设置某个节点的acl权限信息

addauth: 输入认证授权信息,相当于注册用户信息,注册时输入明文密码,zk将以密文的形式存

节点创建的同时设置ACL:

[zk: localhost:2181(CONNECTED) 13] create /zk-node1 123 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa
Created /zk-node1
           

或者用setAcl 设置:

[zk: localhost:2181(CONNECTED) 19] setAcl /zk-node1 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:cdrwa
           

添加授权信息后,不能直接访问,直接访问将报如下异常:

[zk: localhost:2181(CONNECTED) 16] get /zk-node1
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /zk-node1

           

访问前需要添加授权信息:

[zk: localhost:2181(CONNECTED) 1 7] addauth digest user:123456
[zk: localhost:2181(CONNECTED) 18] get /zk-node1
123

           
如果设置权限后,再次致谢setAcl命令,可以覆盖权限,需要重新授权

3. 测试

3.1 schema=Digest例子

格式:

setAcl /test digest:用户名:密码:权限

,密码是用户名和密码加密后的字符串。

3.1.1 代码生成ID

下面代码中有2种形式,输出值不同,一个带user,一个不带user,要特别注意:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.binary.Base64;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;

public class ZkTest {

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // 方式1
        String sId = DigestAuthenticationProvider.generateDigest("user:123456");
        System.out.println(sId); // user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=

        // 方式2
        String usernameAndPassword = "user:123456";
        byte digest[] = MessageDigest.getInstance("SHA1").digest(usernameAndPassword.getBytes());
        Base64 base64 = new Base64();
        String encodeToString = base64.encodeToString(digest);
        System.out.println(encodeToString); // 6DY5WhzOfGsWQ1XFuIyzxkpwdPo=

    }

}

           

3.1.2 xshell生成ID

echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
```例如:

```bash
echo -n root:root | openssl dgst -binary -sha1 | openssl base64
qiTlqPLK7XM2ht3HMn02qRpkKIE=
           

3.1.3 总结

注意,只有通过

zkCli.sh

设置digest的ACL时id才需要密文,而通过zookeeper的客户端设置digest的ACL时对应的auth数据是

明文

。这个属于编码实现的问题了。

在客户端输入addauth digest user:123456添加授权用户,是明文,如果是脚本,则带密文

和auth比较,digest有如下特性:

  • setAcl不需要事先添加认证用户。
  • 授权是针对单个特定用户。
  • setAcl使用的密码不是明文,是sha1摘要值,无法反推出用户密码内容。

3.3 schema=Auth 明文授权

这种授权不针对任何特定ID,而是对所有已经添加认证的用户,换句话说,就是对所有已经通过认证的用户授权。在当前客户端添加auth授权用户,一旦某个节点被加了auth权限,后续不需要每次在执行命令中增加鉴权参数即可访问节点。

用法如下:

addauth digest <user>:<password> 
setAcl <path> auth:<id>:<acl>
           

注意:

  • 必须要先添加认证用户,至少要添加一个认证用户,否则会失败,如下所示:
    [zk: localhost:2181(CONNECTED) 0] create /test 'test'
    [zk: localhost:2181(CONNECTED) 1] setAcl /test auth::crdwa   '从未添加过认证用户,会失败'
    Acl is not valid : /test
               
  • setAcl命令中的id域是被忽略的,可以填任意值,或者空串,例如:

    setAcl <path> auth::crdwa

    ,因为这个域是忽略的,会把所有已经添加的认证用户都加进来
    [zk: localhost:2181(CONNECTED) 2] addauth digest tom1:tom1   '//添加认证用户tom1'
    [zk: localhost:2181(CONNECTED) 3] addauth digest tom2:tom2  '//添加认证用户tom2'
    [zk: localhost:2181(CONNECTED) 4] addauth digest tom3:tom3  '//添加认证用户tom3'
    [zk: localhost:2181(CONNECTED) 5] setAcl /test auth:tom2:crdwa    '//设置认证用户tom2'
    [zk: localhost:2181(CONNECTED) 6] getAcl /test
    'digest,'tom1:ben+k/3JomjGj4mfd4fYsfM6p0A=
    : cdrwa
    'digest,'tom2:2iJM00A7+qkeKdEXt8Bhgq+IACw=
    : cdrwa
    'digest,'tom3:TAZPWLs6IaYRS8mlvcfyCOwyBJ8=
    : cdrwa
               
    这个例子中,我们先添加了三个认证用户tom1,tom2,tom3,然后通过setAcl设置ACL,命令中指定了id为tom2,根据前面的说法,这个id值是被忽略的,写任何值,甚至空值也得到一样的结果。我们看到最后getAcl查询出来的结果包含所有前面添加的三个认证用户。
    其实我不是很理解这个功能,难道在一个会话(session)里可以添加多个认证用户 ,那验证的时候按哪一个算呢;如果不同的用户有不同的授权会导致授权冲突吗?以谁为准?
    几点总结:
    • 1.auth的

      id值是无效

      的,表示给所有认证用户设置acl权限。
      • 1.1. 认证用户的添加,通过addauth命令(addauth digest :),只在当前会话(session)有效。
    • 2.当使用addauth命令添加多个认证用户后,再用auth setAcl来设置acl时,那么所有

      之前addauth的用户

      都被会加入到acl中。
    • 3.如果在当前会话中还没有认证过的用户就使用auth setAcl来设置acl权限时会失败,前面已经讨论过。
    • 4.在auth setAcl

      之后

      再使用addauth添加的认证用户是没有acl权限的,

      必须重新执行

      auth setAcl来设置权限。
    • 5.使用addauth添加的认证用户

      只在当前会话(session)有效

      ,如果此时在另外一个会话中,不添加对应的认证用户,那么就没有相应访问权限的,而且如果再使用auth setAcl来设置acl权限,则会覆盖之前的acl权限信息,而且只会针对当前会话中的认证用户来设置acl权限。
    所以这种授权方式更倾向于用作测试开发环境,而不是产品环境中。

3.3 schema=IP

IP可以是单个IP地址,也可以是IP地址段,比如ip:192.168.1.0/16

setAcl /node‐ip ip:192.168.100.12:cdwra
 create /node‐ip data ip:192.168.100.128:cdwra
           

3.4 schema=world

这是默认方式,表示没有认证。当创建一个新的节点(znode),而又没有设置任何权限时,就是这个值,例如:

[zk: localhost:2181(CONNECTED) 18] create /noacl   '//创建一个节点,没有值,也没有设定权限'
Created /noacl
[zk: localhost:2181(CONNECTED) 19] getAcl /noacl   '//查看权限'
'world,'anyone                         '//显示权限为world'
: cdrwa
           

看到/noacl的ACL属于就是world schema的,因为它没有设置ACL属性,这样任何人都可以访问这个节点。

如果要手工设置这个属性,那么此时的id域只允许一个值,即anyone,格式如下:

setAcl /newznode world:anyone:crdwa
           

参考:

《说说Zookeeper中的ACL》

《zookeeper的ACL权限控制》

《对zookeeper设置ACL属性》 写的比较好,深入浅出