• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

分布式服务Dubbo+Zookeeper安全认证

技术杂谈 勤劳的小蚂蚁 4个月前 (01-05) 73次浏览 已收录 0个评论 扫描二维码

前言
由于之前的服务都是在内网,Zookeeper集群配置都是走的内网IP,外网不开放相关端口,也就不存在安全校验一说。由于业务升级,为了提升服务性能,当购买了云服务+私有云打造混合云的时候,这时如何保证Zookeeper不被任意服务注册消费呢?

问题

Zookeeper+dubbo,如何设置安全认证?不想让其他服务连接Zookeeper,因为这个Zookeeper服务在外网私有云,但是必须开放给公有云。
查询官方文档:
Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。
流程说明:
  • 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
  • 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
  • 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址
支持以下功能:
  • 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
  • 当注册中心重启时,能自动恢复注册数据,以及订阅请求
  • 当会话过期时,能自动恢复注册数据,以及订阅请求
  • 当设置 < dubbo:registry check=”false” /> 时,记录失败注册和订阅请求,后台定时重试
  • 可通过 < dubbo:registry username=”admin” password=”1234″ /> 设置 zookeeper 登录信息
  • 可通过 < dubbo:registry group=”dubbo” /> 设置 zookeeper 的根节点,不设置将使用无根树
  • 支持 * 号通配符 < dubbo:reference group=”” version=”” />,可订阅服务的所有分组和所有版本的提供者
官网文档第五条,明确说明了可以通过username和 password字段设置zookeeper 登录信息。
以下是registry参数说明:
但是,如果在Zookeeper上通过digest方式设置ACL,然后在dubbo registry上配置相应的用户、密码,服务就注册不到Zookeeper上了,会报KeeperErrorCode = NoAuth错误。
但是查阅ZookeeperRegistry相关源码并没有发现相关认证的地方,搜遍全网很少有问类似的问题,这个问题似乎并没有多少人关注。

Zookeeper中的ACL

概述

传统的文件系统中,ACL分为两个维度,一个是属组,一个是权限,子目录/文件默认继承父目录的ACL。而在Zookeeper中,node的ACL是没有继承关系的,是独立控制的。Zookeeper的ACL,可以从三个维度来理解:一是scheme; 二是user; 三是permission,通常表示为
  1. scheme:id:permissions
下面从这三个方面分别来介绍:
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: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication
  • ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
  • super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)

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

  • CREATE(c): 创建权限,可以在在当前node下创建child node
  • DELETE(d): 删除权限,可以删除当前的node
  • READ(r): 读权限,可以获取当前node的数据,可以list当前node所有的child nodes
  • WRITE(w): 写权限,可以向当前node写数据
  • ADMIN(a): 管理权限,可以设置当前node的permission

客户端管理

我们可以通过以下命令连接客户端进行操作:
  1. ./zkCli.sh

帮助

  1. [zk: localhost:2181(CONNECTED)2] help
  2. ZooKeeper-server host:port cmd args
  3.        connect host:port
  4.        get path [watch]
  5.        ls path [watch]
  6.        set path data [version]
  7.        rmr path
  8.        delquota [-n|-b] path
  9.        quit
  10.        printwatches on|off
  11.        create [-s][-e] path data acl
  12.        stat path [watch]
  13.        close
  14.        ls2 path [watch]
  15.        history
  16.        listquota path
  17.        setAcl path acl
  18.        getAcl path
  19.        sync path
  20.        redo cmdno
  21.        addauth scheme auth
  22.        delete path [version]
  23.        setquota -n|-b val path

简单操作

  1. [zk: localhost:2181(CONNECTED)12] ls /
  2. [dubbo, test, zookeeper]
  3. [zk: localhost:2181(CONNECTED)13] create /itstyle  data ip:192.168.1.190:cdrw
  4. Created/itstyle
  5. [zk: localhost:2181(CONNECTED)14] getAcl /itstyle
  6. 'ip,'192.168.1.190
  7. : cdrw

zkclient操作代码

  1. import java.security.NoSuchAlgorithmException;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Map;
  5. import org.I0Itec.zkclient.ZkClient;
  6. import org.apache.zookeeper.ZooDefs;
  7. import org.apache.zookeeper.data.ACL;
  8. import org.apache.zookeeper.data.Id;
  9. import org.apache.zookeeper.data.Stat;
  10. import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
  11. publicclassAcl{
  12.    privatestaticfinalString zkAddress ="192.168.1.190:2181";  
  13.    privatestaticfinalString testNode ="/dubbo";  
  14.    privatestaticfinalString readAuth ="read-user:123456";  
  15.    privatestaticfinalString writeAuth ="write-user:123456";  
  16.    privatestaticfinalString deleteAuth ="delete-user:123456";  
  17.    privatestaticfinalString allAuth ="super-user:123456";  
  18.    privatestaticfinalString adminAuth ="admin-user:123456";  
  19.    privatestaticfinalString digest ="digest";  
  20.    privatestaticvoid initNode()throwsNoSuchAlgorithmException{  
  21.        ZkClient zkClient =newZkClient(zkAddress);  
  22.        System.out.println(DigestAuthenticationProvider.generateDigest(allAuth));
  23.        zkClient.addAuthInfo(digest, allAuth.getBytes());  
  24.        if(zkClient.exists(testNode)){  
  25.            zkClient.delete(testNode);  
  26.            System.out.println("节点删除成功!");  
  27.        }  
  28.        List<ACL> acls =newArrayList<ACL>();  
  29.        acls.add(new ACL(ZooDefs.Perms.ALL,newId(digest,DigestAuthenticationProvider.generateDigest(allAuth))));
  30.        acls.add(new ACL(ZooDefs.Perms.ALL,newId(digest,DigestAuthenticationProvider.generateDigest(allAuth))));  
  31.        acls.add(new ACL(ZooDefs.Perms.READ,newId(digest,DigestAuthenticationProvider.generateDigest(readAuth))));  
  32.        acls.add(new ACL(ZooDefs.Perms.WRITE,newId(digest,DigestAuthenticationProvider.generateDigest(writeAuth))));  
  33.        acls.add(new ACL(ZooDefs.Perms.DELETE,newId(digest,DigestAuthenticationProvider.generateDigest(deleteAuth))));  
  34.        acls.add(new ACL(ZooDefs.Perms.ADMIN,newId(digest,DigestAuthenticationProvider.generateDigest(adminAuth))));  
  35.        zkClient.createPersistent(testNode, testNode, acls);  
  36.        System.out.println(zkClient.readData(testNode));  
  37.        System.out.println("节点创建成功!");  
  38.        zkClient.close();  
  39.    }  
  40.    privatestaticvoid readTest(){  
  41.        ZkClient zkClient =newZkClient(zkAddress);  
  42.        try{  
  43.            System.out.println(zkClient.readData(testNode));//没有认证信息,读取会出错  
  44.        }catch(Exception e){  
  45.            System.err.println(e.getMessage());  
  46.        }  
  47.        try{  
  48.            zkClient.addAuthInfo(digest, adminAuth.getBytes());  
  49.            System.out.println(zkClient.readData(testNode));//admin权限与read权限不匹配,读取也会出错  
  50.        }catch(Exception e){  
  51.            System.err.println(e.getMessage());  
  52.        }  
  53.        try{  
  54.            zkClient.addAuthInfo(digest, readAuth.getBytes());  
  55.            System.out.println(zkClient.readData(testNode));//只有read权限的认证信息,才能正常读取  
  56.        }catch(Exception e){  
  57.            System.err.println(e.getMessage());  
  58.        }  
  59.        zkClient.close();  
  60.    }  
  61.    privatestaticvoid writeTest(){  
  62.        ZkClient zkClient =newZkClient(zkAddress);  
  63.        try{  
  64.            zkClient.writeData(testNode,"new-data");//没有认证信息,写入会失败  
  65.        }catch(Exception e){  
  66.            System.err.println(e.getMessage());  
  67.        }  
  68.        try{  
  69.            zkClient.addAuthInfo(digest, writeAuth.getBytes());  
  70.            zkClient.writeData(testNode,"new-data");//加入认证信息后,写入正常  
  71.        }catch(Exception e){  
  72.            System.err.println(e.getMessage());  
  73.        }  
  74.        try{  
  75.            zkClient.addAuthInfo(digest, readAuth.getBytes());  
  76.            System.out.println(zkClient.readData(testNode));//读取新值验证  
  77.        }catch(Exception e){  
  78.            System.err.println(e.getMessage());  
  79.        }  
  80.        zkClient.close();  
  81.    }  
  82.    privatestaticvoid deleteTest(){  
  83.        ZkClient zkClient =newZkClient(zkAddress);  
  84.        zkClient.addAuthInfo(digest, deleteAuth.getBytes());  
  85.        try{  
  86.            System.out.println(zkClient.readData(testNode));  
  87.            zkClient.delete(testNode);  
  88.            System.out.println("节点删除成功!");  
  89.        }catch(Exception e){  
  90.            System.err.println(e.getMessage());  
  91.        }  
  92.        zkClient.close();  
  93.    }  
  94.    privatestaticvoid changeACLTest(){  
  95.        ZkClient zkClient =newZkClient(zkAddress);  
  96.        //注:zkClient.setAcl方法查看源码可以发现,调用了readData、setAcl二个方法  
  97.        //所以要修改节点的ACL属性,必须同时具备read、admin二种权限  
  98.        zkClient.addAuthInfo(digest, adminAuth.getBytes());  
  99.        zkClient.addAuthInfo(digest, readAuth.getBytes());  
  100.        try{  
  101.            List<ACL> acls =newArrayList<ACL>();  
  102.            acls.add(new ACL(ZooDefs.Perms.ALL,newId(digest,DigestAuthenticationProvider.generateDigest(adminAuth))));  
  103.            zkClient.setAcl(testNode, acls);  
  104.            Map.Entry<List<ACL>,Stat> aclResult = zkClient.getAcl(testNode);  
  105.            System.out.println(aclResult.getKey());  
  106.        }catch(Exception e){  
  107.            System.err.println(e.getMessage());  
  108.        }  
  109.        zkClient.close();  
  110.    }  
  111.    publicstaticvoid main(String[] args)throwsException{  
  112.        initNode();  
  113.        System.out.println("---------------------");  
  114.        readTest();  
  115.        System.out.println("---------------------");  
  116.        writeTest();  
  117.        System.out.println("---------------------");  
  118.        changeACLTest();  
  119.        System.out.println("---------------------");  
  120.        deleteTest();  
  121.    }  
  122. }

总结

在私有云中服务大都是部署在内网的,基本很少对外网开放,然而DubboZooKeeper用户权限认证貌似真的不起作用?在跨网注册的情况下,如果非要对外开放只能通过iptables或者firewall进行IP Access Control,当然搭建VPN隧道也是一个不错的选择。
2018年1月9日在dubbo/issues上看到这样一句话,不知道是否可行。
Currently, dubbo support digest ACL provided by zookeeper. And you must use curator, because zkclient don’t support zookeeper’s ACL.

扩展

不过据说阿里内部服务并不使用ZooKeeper作为注册中心,而是使用自研的Nacos,目前Nacos已启动开源计划(阅读原文)。
阿里巴巴将通过Dubbo + Nacos以及一系列开源项目打造服务发现、服务及流量管理、服务共享平台。
Nacos会无缝支持Spring Cloud,为Spring Cloud用户其提供更简便的配置中心和注册中心的解决方案,使用Nacos不用再仅仅为服务和配置就需要在生产上hold住 Eureka,Spring Cloud Config Server,Git,RabbitMQ/Kafka 起码四个开源产品。

丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:分布式服务Dubbo+Zookeeper安全认证
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00