概述
最近项目应客户要求Zookeeper需要认证,只有认证通过连接才能建立。但是有个比较尴尬的情况,我们项目本身也连接kafka,kafka之前做过kerborse认证。那么该如何做能让一个java进程存在多种认证方式呢?
Zookeeper Server搭建
本节讲解如何搭建基于SASL digest-md5方式的Zookeeper server。
- 下载zookeeper
下载地址:www.apache.org/dyn/closer.…
下载并且解压。
- 修改配置zoo.cfg
解压目录中的conf目录修改zoo.cfg, 如果没有的话,复制zoo_sample.cfg一份,命名为zoo.cfg, 添加sasl认证相关的配置:
sessionRequireClientSASLAuth=true authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
- sessionRequireClientSASLAuth: zk3.6.0版本中添加,为true时要求客户端连接zk时必须进行SASL认证才可以连接成功,也就是说没有进行SASL认证的匿名用户就无法连接了,相当于在连接时设置了一个登录密码。
- authProvider.1: zk的认证方式,可以为ZooKeeper指定多个认证提供程序类。通常使用此参数指定
SASLAuthenticationProvider
- 添加认证文件jaas.conf
Server { org.apache.zookeeper.server.auth.DigestLoginModule required user_super="adminsecret" user_bob="bobsecret"; };
- 提供了两个用户super和bob,他们的密码分别是"adminsecret"和"bobsecret"。
- 请注意,上面的密码都是纯文本,所以除了ZooKeeper服务器进程用户之外,JAAS配置文件应该不能被其他人读取。
- 添加server启动参数java.env
在conf目录下添加java.env,内容如下:
SERVER_JVMFLAGS="-Djava.security.auth.login.config=/home/dev/soft/sasl/conf/jaas.conf"
指定jaas.conf的路径,zkServer启动的时候会读取java.env,作为启动参数。
- 启动
执行下面命令启动zkServer。
./bin/zkServer.sh start
- 通过zkCli验证
不做任何修改,直接执行./bin/zkCli.sh
开启客户端,会报错如下
那怎么办呢?我们用java客户端演示一下。
JAVA客户端连接认证Zookeeper
- 创建认证文件jaas.conf
- 创建Zookeeper代码
@Before public void init() throws IOException, InterruptedException { System.setProperty("java.security.auth.login.config", "D:\Developer\CodeRepo\alvinlkk\awesome-java-full-demo\zookeeper-demo\zookeeper-sasl-demo\src\main\resources\jaas.conf"); log.info("********************** start zk .................."); CountDownLatch countDownLatch = new CountDownLatch(1); zooKeeper = new ZooKeeper(ZK_ADDR, ZK_SESSION_TIMEOUT, event -> { log.info("%%%%%%%%%%%%%%%%%%%%%触发了事件:[{}]", event); countDownLatch.countDown(); }); countDownLatch.await(); }
- 关键步骤在于设置系统属性
System.setProperty("java.security.auth.login.config", "D:\jaas.conf");
- 正常创建和读取节点
@Test public void testGet() throws InterruptedException, KeeperException { Stat stat = new Stat(); byte[] data = zooKeeper.getData("/node1", false, stat); log.info("获取到的数据是:" + new String(data)); log.info("当前节点的版本:" + stat.getVersion()); }
- 设置jaas到系统属性中后,创建、读取节点就不会报错。
Kafka和Zookeeper同时认证
回到一开始的问题,Kafka的kerberos认证也是通过修改系统属性,如下图:
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); System.setProperty("java.security.krb5.conf", "D:\krb5.conf"); System.setProperty("java.security.auth.login.config", "D:\jaas.conf");
那这样会不会和前面的zookeeper配置冲突呢?
实际情况不会,可以在jaas.cfg中写多份配置信息,通过前面的KafkaClient和Client做为区分,他们是Kafka和Zookeeper客户端默认的名字,也可以通过配置修改。
SASL相关知识
SASL是一种用来扩充C/S模式验证能力的机制认证机制, 全称Simple Authentication and Security Layer,常见的机制如下:
- plain(较常用)
plain是最简单的机制,但同时也是最危险的机制,因为身份证书(登录名称与密码)是以base64字符串格式通过网络,没有任何加密保护措施。因此,使用plain机制时,你可能会想要结合tls。
- login
login不是其正式支持的机制,但某些旧版的mua使用这种机制,所以cyrus sasl让你可选择其是否支持login机制。如果你的用户仍在使用这类老掉牙的mua,你必须在编译sasl函数库时,指定要包含login的支持。 login的证书交换过程类似plain。
- otp
otp是一种使用“单次密码”的验证机制。此机制不提供任何加密保护,因为没必要每个密码都只能使用一次,每次联机都要改用新密码。smto client必须能够产生otp证书。
- digest-md5(较常用)
使用这种机制时,client与server共享同一个隐性密码,而且此密码不通过网络传输。验证过程是从服务器先提出challenge(质询)开始, 客户端使用此challenge与隐性密码计算出一个response(应答)。不同的challenge,不可能计算出相同的response;任何拥 有secret password的一方,都可以用相同的challenge算出相同的response。因此,服务器只要比较客户端返回的response是否与自己算 出的response相同,就可以知道客户端所拥有的密码是否正确。由于真正的密码并没有通过网络,所以不怕网络监测。
- kerberos
kerberos是一种网络型验证协议。除非你的网络已经使用kerberos,否则你应该用不到kerberos机制;相对的,如果你的网络已经架设了kerberos验证中心,sasl就能完美的将smtp验证整合进现有的体系。
总结
本文重点还是在于zookeeper如何进行认证,希望能够帮助到大家,文中的代码参考地址:github.com/alvinlkk/aw…。