Dubbo+Zookeeper ACL+ElasticJob

本文详细介绍了在Zookeeper开启ACL后,如何配置Dubbo和Elastic-Job以安全连接Zookeeper。首先,展示了在Zookeeper客户端设置/dubbo目录的ACL权限,然后分别讲解了在SpringBoot配置文件中添加dubbo.registry.username和password的步骤。对于Elastic-Job,建议将namespace设为dubbo.registry.group的值以简化配置。接着,分析了dubbo和elastic-job的源码,发现dubbo在创建目录时未设置ACL,而elastic-job创建的子目录权限与配置一致。最后,讨论了当前存在的安全风险,如dubbo服务目录权限过于开放。

一. 问题背景

当Zookeeper开启ACL后,Dubbo以及Elastic-Job需要如何配置来连接Zookeeper。

Zookeeper ACL介绍参考文章: https://cloud.tencent.com/developer/article/1414462

二. 组件版本

  1. zookeeper: 3.5.8
  2. dubbo: 2.6.6
  3. elastic-job: 1.0.6

三. ZK设置ACL

3.1 dubbo

dubbo默认是注册在/dubbo目录,下面以/dubbo目录为例说明。

1. 进入Zookeeper客户端,创建/dubbo目录及设置ACL权限。

$ create /dubbo 'data'
$ addauth digest hamawhite:123456

$ setAcl /dubbo auth:hamawhite:123456:cdwra
$ getAcl /dubbo

'digest,'hamawhite:YfjnOH3mtKecIPZ5prmNB7B6lA4=
: cdrwa

2.   修改SpringBoot的配置文件,增加duboo registry的username和password。

dubbo.registry.username=hamawhite
dubbo.registry.password=123456

如果Zookeeper管理员分配给指定的目录来注册,例如 /gou,则需要在dubbo的配置文件中还需增加 dubbo.registry.group=/shuqi 。

完整配置如下:

dubbo.registry.group=shuqi
dubbo.registry.username=hamawhite
dubbo.registry.password=123456

3.2 elastic-job

推荐把elastic-job的namespace配置为dubbo.registry.group的值,否则Zookeeper管理员还需要给elastic-job额外分配目录。

完整配置如下:

    <!--配置作业注册中心 -->
    <reg:zookeeper id="regCenter"
                   serverLists="${dubbo.registry.address}"
                   namespace="${dubbo.registry.group}"
                   digest="${dubbo.registry.username}:${dubbo.registry.password}"
                   baseSleepTimeMilliseconds="1000"
                   maxSleepTimeMilliseconds="3000"
                   maxRetries="0"/>

注意,在SpringBoot的配置中一定要定义dubbo.registry.group,如果是默认值,也要写dubbo.registry.group=dubbo。

四. ZK目录探索

4.1 dubbo registry目录

dubbo在/dubbo目录下注册的service都未设置ACL,权限都是world:anyone:cdrwa。这样其实任意用户能访问此service目录,仍有安全风险。

[zk: localhost:2181(CONNECTED) 64] getAcl /dubbo/com.dtwave.ai.api.service.ModelService
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 65] getAcl /dubbo/com.dtwave.ai.api.service.NotebookService
'world,'anyone
: cdrwa

4.2 dubbo 源码分析

dubbo2.6版本后Zookeeper客户端默认是Curator,因此查看com.alibaba.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient的代码。

创建client代码如下:

    public CuratorZookeeperClient(URL url) {
        super(url);
        try {
            CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(1, 1000))
                    .connectionTimeoutMs(5000);
            String authority = url.getAuthority();
            if (authority != null && authority.length() > 0) {
                builder = builder.authorization("digest", authority.getBytes());
            }
            client = builder.build();
            client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                @Override
                public void stateChanged(CuratorFramework client, ConnectionState state) {
                    if (state == ConnectionState.LOST) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
                    } else if (state == ConnectionState.CONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
                    } else if (state == ConnectionState.RECONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
                    }
                }
            });
            client.start();
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

可以看到,创建client的时候有处理授权,builder = builder.authorization("digest", authority.getBytes()) ,也未设置aclProvider。

在创建目录时候,也未设置ACL。 因此子目录权限都是默认的world:anyone:cdrwa。

    @Override
    public void createPersistent(String path) {
        try {
            client.create().forPath(path);
        } catch (NodeExistsException e) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    @Override
    public void createEphemeral(String path) {
        try {
            client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
        } catch (NodeExistsException e) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

补充创建目录可以通过配置withACL来设置ACL,示例代码如下:

具体可参考 https://blog.youkuaiyun.com/liuxiao723846/article/details/85303602

client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(acls).forPath(nodePath, nodeData);

4.3 elastic-job zookeeper目录

elastic-job在/dubbo目录下创建的子目录用户名和密码和配置项保持一致,permission权限都是cdrwa。

[zk: localhost:2181(CONNECTED) 66] getAcl /dubbo/updateNotebookStatusJob
'digest,'hamawhite:YfjnOH3mtKecIPZ5prmNB7B6lA4=
: cdrwa
[zk: localhost:2181(CONNECTED) 67] ls /dubbo/updateNotebookStatusJob
[config, execution, leader, servers]
[zk: localhost:2181(CONNECTED) 68] getAcl /dubbo/updateNotebookStatusJob/leader
'digest,'hamawhite:YfjnOH3mtKecIPZ5prmNB7B6lA4=
: cdrwa

4.4 elastic-job Zookeeper客户端源码分析

查看com.dangdang.ddframe.reg.zookeeper.ZookeeperRegistryCenter的代码。

创建client 核心代码如下:

    public void init() {
        ......

        if (!Strings.isNullOrEmpty(this.zkConfig.getDigest())) {
            builder.authorization("digest", this.zkConfig.getDigest().getBytes(Charset.forName("UTF-8"))).aclProvider(new ACLProvider() {
                public List<ACL> getDefaultAcl() {
                    return Ids.CREATOR_ALL_ACL;
                }

                public List<ACL> getAclForPath(String path) {
                    return Ids.CREATOR_ALL_ACL;
                }
            });
        }

        this.client = builder.build();
        this.client.start();

        try {
            this.client.blockUntilConnected();
            if (!Strings.isNullOrEmpty(this.zkConfig.getLocalPropertiesPath())) {
                this.fillData();
            }
        } catch (Exception var3) {
            RegExceptionHandler.handleException(var3);
        }

    }

可以看到,创建client的时候有处理授权,builder = builder.authorization("digest", authority.getBytes()) ,设置了aclProvider。

其中perms设置为全部权限,即cdrwa。Ids设置为AUTH_IDS,表示会继承客户端的身份鉴权信息。

      /**
         * This ACL gives the creators authentication id's all permissions.
         */
        public final ArrayList<ACL> CREATOR_ALL_ACL = new ArrayList<ACL>(
                Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));

       /**
         * This Id is only usable to set ACLs. It will get substituted with the
         * Id's the client authenticated with.
         */
        public final Id AUTH_IDS = new Id("auth", "");

 

这样CreateBuilderImpl里的 acling = new ACLing(client.getAclProvider()),后续用client创建的子目录用户名和密码和配置项保持一致,permission权限都是cdrwa。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值