dubbo与zookeeper权限关联

一、背景

在日常生产中最常用使用zookeeper作为dubbo注册中心使用,但是经常在使用过程中,由于安全扫描,出现zookeeper未授权访问漏洞,需要对zookeeper节点添加权限,但是dubbo至今没有增加zookeeper权限控制功能,所以需要自己改造源码实现。

二、zookeeper简单介绍

zookeeper是分布式服务架构,主要用来解决分布式应用中经常遇到的一些数据管理问题,比如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

zookeeper上节点最常用的5种操作权限:

Create、Read、Write、Delete、Admin也就是增、删、改、查、管理权限,简写crwda

(这五种权限中,delete是指对子节点删除权限,其他四种权限指本身节点权限)

身份验证有4中方式:

  • world:有个单一的ID,anyone,表示任何人。
  • auth:不使用任何ID,表示任何通过验证的用户(是通过ZK验证的用户?连接到此ZK服务器的用户?)。
  • digest:使用 用户名:密码
    字符串生成MD5哈希值作为ACL标识符ID。权限的验证通过直接发送用户名密码字符串的方式完成,
  • ip:使用客户端主机ip地址作为一个ACL标识符,ACL表达式是以 addr/bits
    这种格式表示的。ZK服务器会将addr的前bits位与客户端地址的前bits位来进行匹配验证权限。

看到了授权需要的模式是secheme🆔perm形式,下面就说说secheme

secheme介绍

  • world表示所有。创建节点的默认权限,有唯一的id是anyone授权的时候模式为world:anyone:rwcda
    表示所有人都有对这个节点的rwcda权限。这里用的是id,而不是expression。
  • auth不需要id。不过这里应该用expression来表示。
  • digest使用用户名:密码编码成md5的方式作为访问权限列表id。但是这里id不作为授权语句的一部分,这里也是用expression方式。用户名:密码先进行shal编码后再用base64编码。这个比较恶心。
  • host使用用户主机作为访问空着列表的id。但是这里需要注意的是表达式用的主句的后缀即可。举个栗子:如果表达式设置为
    corp.com 可以匹配 host1.corp.com 和
    host2.corp.com的主机名,但是host1.zookeeper.com则不能匹配。
  • ip:跟主机名类似。这里使用客户端的ip地址作为权限访问列表的id。表达式可以用
    addr/bits这种方式设置ip白名单。

常用加密命令:

方法一、auth设置权限

  • 设置这个权限之前首先需要

addauth digest zookeeper:zookeeper

  • 然后再设置auth

setAcl /test auth:zookeeper:zookeeper:crwda

  • 检查权限

getAcl /test

  • 可以看到权限已经设置成功了。

get /test

方法二、digest设置权限 (这个里面有个大坑)

可以看出比较明显的:

  1. 设置之前不需要通过addauth添加对应的授权认证,而是直接授权便可。
  2. 命令行设置了什么,然后在获取对应的权限的时候就会把对应的字符串显式记录下来,而不会进行任何编码,
    如上面的zookeeper:zookeeper。这种方式就需要自己去编码了。
  3. 这也是个比较坑爹的事情,设置密码之前需要把密码先自己进行sha1编码然后吧结果进行base64编码。如果编码的方式错误你将永远失去这个节点的访问权。不编码就访问不了

使用sha1编码和base64编码之后设置digest方式保存起来

之后就可以使用addauth的方式访问啦

使用代码连接创建带权限的zookeeper节点

创建节点数据时:

读取Zookeeper数据时:

三、dubbo如何使用zookeeper作为注册中心

通常使用dubbo一般有四种方式,xml配置、API调用、properties加载、注解配置。使用zookeeper作为注册中心主要配置如下:

  1. xml schema扩展

  1. properties配置

  1. API代码设置

  1. 注解配置

四、dubbo实现zookeeper权限关联

最近又把dubbo拾起来啦,以前用过dubbo,后来12年阿里巴巴不维护啦,后来随着springcloud的不断崛起,使用dubbo的人越来越少,但是在国内还是有好多dubbo的热爱着,也是因为这样,在2017年的时候阿里将dubbo奉献给Apache社区,后面估计会越来越好。

这个无论是之前阿里维护还是现在放到Apache社区,直到目前为止,dubbo都没做好这块,使用zookeeper加权限连接,其实挺简单的,下面大致讲以下怎么做。

这里做之前先说一下实现dubbo连接加权限的zookeeper有两种方式,这个取决于dubbo连接zookeeper是通过两种客户端连接的,分别是zkclient和curator,而且dubbo提前预留量注册中心变量设置用户名和密码,这里使用的zookeeper加权方式是digest方式,使用用户名和密码方式对zookeeper节点加权限。

这里需要注意的是,自从dubbo转到Apache下面之后,源码改动不少,其中在dubbo
2.6.0以后版本,dubbo将默认使用zkclient访问zookeeper改成了默认使用curator客户端访问
而且在2.5.4版本之后将com.github.sgroschupf 下面的zkclient 0.1版本改成了
com.101tec 下面的zkclient 0.2版本啦。

1、改造zkclient客户端dubbo源码实现

  • 替换zkclient jar包

这里无论是新版本还是旧版本,都需要将zkclient包替换成com.101tec
的0.5以上版本
,因为只有0.5以上的版本才支持ACL加权控制。(本人建议使用0.8以上的版本)

如果你是2.5.4以前的版本(包括2.5.4版本,就是12年之后17年之前发布的最新版本)需要将

替换成

(这个之前版本比较麻烦,需要到源码中将所有的pom都需要修改)

如果你是使用2.5.4以后的版本比较简单,只需要将dubbo-parent中的

<zkclient_version>0.2</zkclient_version>

改成

<zkclient_version>0.8</zkclient_version>

  • dubbo使用zkclient客户端源码解析

这里简单的介绍也一下dubbo连接Zookeeper的实现原理,首先服务的提供者和消费者在RegistryProtocol利用注册中心暴露(export)和引用(refer)服务的时候会根据配置利用Dubbo的SPI机制获取具体注册中心注册器

这里的RegistryFactory是ZookeeperRegistryFactory看如下工厂代码

在这里创建zookeepr注册器ZookeeperRegistry。

ZookeeperTransporter是操作zookeepr的客户端的工厂类,用来创建zookeeper客户端,这里客户端并不是zookeeper源代码的自带的,而是采用第三方工具包,主要来简化对zookeeper的操作,例如用zookeeper做注册中心需要对zookeeper节点添加watcher做反向推送,但是每次回调后节点的watcher都会被删除,这些客户会自动维护了这些watcher,在自动添加到节点上去。

  • dubbo源码改造适配zookeeper添加ACL权限

这里又要分版本对待,对dubbo添加zookeeper权限适应于2.2.0-2.5.6版本之间dubbo使用者,2.5.6之后版本添加了ZkClientWrapper类,对zkclient又做成守护线程形式,需要进一步改造,后面也会专门提高2.5.6之后怎么改造的。

适配2.2.0-2.5.6版本之间dubbo源码改造

  1. 在使用zkClient
    连接Zookeeper中最重要的一个类是ZkclientZookeeperClient,Zookeeper的连接、节点创建和节点访问都在这个类中,我们需要重点改造的类。

  1. ZkclientZookeeperClient在构造函数中创建连接Zookeeper,在连接的时候使用用户名密码连接:

  1. 将ZkclientZookeeperClient中的“createPersistent(String
    path)”和“createEphemeral(String path)”创建节点设置权限:

到目前为止,源码就改动这么多,连接Zookeeper的用户名和密码通过dubbo配置注册中心的时候配置,通过spring加载代URL中。
然后下面就说说具体怎么配置怎么用。

  1. 改造后的dubbo连接Zookeeper配置

从 2.2.0 版本开始缺省为 zkclient 实现,以提升 zookeeper 客户端的健状性,配置:

<dubbo:registry ... client="zkclient" username="admin" password="admin" />

dubbo.registry.client=zkclient

dubbo.registry.username=admin

dubbo.registry.password=admin

zookeeper://10.20.153.10:2181?client=zkclient&username=admin&password=admin

到此直接启动即可,dubbo就可自动对注册dubbo的group节点添加ACL权限。

适配2.5.6以上版本dubbo源码改造

  1. 添加handleSessionEstablishmentError监控方法

  1. 重写ZkClientWrapper构造方法

  1. 针对client.start();设置权限登录

  1. 修改ZkClientWrapper类中“createPersistent(String
    path)”和“createEphemeral(String path)”创建节点设置权限:

到目前为止,源码就改动这么多,连接Zookeeper的用户名和密码通过dubbo配置注册中心的时候配置,通过spring加载代URL中。
然后下面就说说具体怎么配置怎么用。

  1. 改造后的dubbo连接Zookeeper配置

从 2.2.0 版本开始缺省为 zkclient 实现,以提升 zookeeper 客户端的健状性,配置:

<dubbo:registry ... client="zkclient" username="admin" password="admin" />

dubbo.registry.client=zkclient

dubbo.registry.username=admin

dubbo.registry.password=admin

zookeeper://10.20.153.10:2181?client=zkclient&username=admin&password=admin

到此直接启动即可,dubbo就可自动对注册dubbo的group节点添加ACL权限。

2、改造curator客户端dubbo源码实现

改造curator是最简单的方式,因为dubbo使用curator已经考虑到zookeeper加ACL了,只是代码设置不生效罢了,只要稍微动一下即可。

  1. 修改CuratorZookeeperClient源码

  1. 改造后的dubbo连接Zookeeper配置

从 2.6.0 版本开始缺省为 curator 实现,以提升 zookeeper 客户端的健状性,配置:

<dubbo:registry ... client="curator" username="admin" password="admin" />

dubbo.registry.client=curator

dubbo.registry.username=admin

dubbo.registry.password=admin

zookeeper://10.20.153.10:2181?client=curator&username=admin&password=admin

启动之后即可实现对zookeeper添加权限控制啦。

至此源码已经全部修改完成。

posted @ 2020-01-03 14:11  GC_AIDM  阅读(3265)  评论(0编辑  收藏  举报