本主要介紹在 Zookeeper 中如何配置 Kerberos 認證,文中所使用到的軟件版本:Java 1.8.0_191、Zookeeper 3.6.3、Kerberos 1.15.1。
1、Kerberos 安裝
要使用 Kerberos 服務,需先安裝 Kerberos,安裝方法可參考:Kerberos 入門實戰(2)--Kerberos 安裝及使用。
2、Client-Server 的 Kerberos 認證
Client-Server 的 Kerberos 認證主要用於客戶端與 Zookeeper 服務端的相互認證。
2.1、單節點 Client-Server 的 Kerberos 認證
2.1.1、創建 keytab
在安裝 Kerberos 的機器上進入 kadmin(Kerberos 服務端上使用 kadmin.local,安裝了 Kerberos Client 的機器上可以使用 kadmin),然后執行如下命令分別創建服務端和客戶端的 keytab:
kadmin.local: add_principal -randkey zk-server/pxc2@ABC.COM #pxc2 為安裝 Zookeeper 的主機名 kadmin.local: add_principal -randkey zk-client@ABC.COM kadmin.local: xst -k /root/zk-server.keytab zk-server/pxc2@ABC.COM kadmin.local: xst -k /root/zk-client.keytab zk-client@ABC.COM
2.1.2、配置
A、拷貝 krb5.conf 及 keytab 文件到安裝 Zookeeper 的機器,這里把文件都放到 Zookeeper 的 conf 目錄下。
B、修改 zoo.cfg,增加如下配置:
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider jaasLoginRenew=3600000 sessionRequireClientSASLAuth=true #客戶端必須 SASL 認證
C、新建 jaas.conf 文件,該文件也放到 Zookeeper 的 conf 目錄下。
Server { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/zk-server.keytab" storeKey=true useTicketCache=false principal="zk-server/pxc2@ABC.COM"; }; #客戶端配置,方便 zkCli.sh 使用 Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/zk-client.keytab" storeKey=true useTicketCache=false principal="zk-client@ABC.COM"; };
D、新建 java.env 文件;該文件主要用於指定 jaas 文件位置,也放到 Zookeeper 的 conf 目錄下。
export SERVER_JVMFLAGS="-Djava.security.auth.login.config=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/jaas.conf -Djava.security.krb5.conf=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/krb5.conf" export CLIENT_JVMFLAGS="${CLIENT_JVMFLAGS} -Djava.security.auth.login.config=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/jaas.conf -Djava.security.krb5.conf=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/krb5.conf -Dzookeeper.server.principal=zk-server/pxc2@ABC.COM"
SERVER_JVMFLAGS 是服務端(zkServer.sh)的配置
CLIENT_JVMFLAGS 是客戶端(zkClis.sh)的配置,zookeeper.server.principal 參數用於配置服務端 principal(默認為 zookeeper/localhost@{realm},可能不存在)
2.1.3、啟動並測試
配置完成后就可以啟動 Zookeeper 了:
bin/zkServer.sh start
啟動完成后可以使用 zkCli.sh 來測試:
bin/zkCli.sh
2.1.4、java 程序連接 Zookeeper
java 可以使用 JAAS 來進行 Kerberos 認證,需要 JAAS 配置文件、keytab 文件及 Kerberos 配置文件。
A、配置文件
JAAS 配置文件(zk-client-jaas.conf):
Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client.keytab" storeKey=true useTicketCache=false principal="zk-client@ABC.COM"; };
keytab 文件:
從 Kerberos 服務器上拷貝到目標機器,拷貝路徑即為 JAAS 配置中間配置的路徑:D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client.keytab。
Kerberos 配置文件(krb5.conf):
從 Kerberos 服務器上拷貝 /etc/krb5.conf 到目標機器即可。
B、引入依賴
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.3</version> </dependency>
C、樣例程序
package com.abc.demo.general.zookeeper; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; /** * Zookeeper 客戶端 Kerberos 認證 */ public class ZookeeperKerberosCase { private static String connectString = "10.49.196.11:2181"; private static int sessionTimeout = 200 * 1000; private ZooKeeper zooKeeper; @Before public void before() { System.setProperty("java.security.auth.login.config", "D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client-jaas.conf"); System.setProperty("java.security.krb5.conf", "D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\krb5.conf"); System.setProperty("zookeeper.server.principal", "zk-server/pxc2@ABC.COM"); //設置 Zookeeper 的 principal try { zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override public void process(WatchedEvent watchedEvent) { } }); System.out.println(zooKeeper.getState()); } catch (IOException e) { e.printStackTrace(); } } @After public void after() throws Exception { zooKeeper.close(); } @Test public void getData() throws Exception { Stat stat = new Stat(); byte[] data = zooKeeper.getData("/javatest/node1", false, stat); System.out.println(new String(data)); System.out.println(stat); } }
2.2、集群 Client-Server 的 Kerberos 認證
假設 Zookeeper 集群的機器信息如下:
ip | 主機名 |
10.49.196.10 | pxc1 |
10.49.196.11 | pxc2 |
10.49.196.12 | pxc3 |
2.2.1、創建 keytab
在安裝 Kerberos 的機器上進入 kadmin(Kerberos 服務端上使用 kadmin.local,安裝了 Kerberos Client 的機器上可以使用 kadmin),然后執行如下命令分別創建服務端和客戶端的 keytab:
kadmin.local: add_principal -randkey zk-server/pxc1@ABC.COM kadmin.local: add_principal -randkey zk-server/pxc2@ABC.COM kadmin.local: add_principal -randkey zk-server/pxc3@ABC.COM kadmin.local: add_principal -randkey zk-client@ABC.COM kadmin.local: xst -k /root/zk-server.keytab zk-server/pxc1@ABC.COM kadmin.local: xst -k /root/zk-server.keytab zk-server/pxc2@ABC.COM kadmin.local: xst -k /root/zk-server.keytab zk-server/pxc3@ABC.COM kadmin.local: xst -k /root/zk-client.keytab zk-client@ABC.COM
2.2.2、配置
A、拷貝 krb5.conf 及 keytab 文件到所有安裝 Zookeeper 的機器,這里把文件都放到 Zookeeper 的 conf 目錄下。
B、修改 zoo.cfg,增加如下配置:
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
jaasLoginRenew=3600000 sessionRequireClientSASLAuth=true #客戶端必須 SASL 認證
C、新建 jaas.conf 文件,該文件也放到 Zookeeper 的 conf 目錄下。
Server {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true keyTab="/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/zk-server.keytab" storeKey=true useTicketCache=false principal="zk-server/pxc1@ABC.COM"; #這里不同的主機上,需修改為本機的主機名 }; #客戶端配置,方便 zkCli.sh 使用 Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/zk-client.keytab" storeKey=true useTicketCache=false principal="zk-client@ABC.COM"; };
D、新建 java.env 文件;該文件主要用於指定 jaas 文件位置,也放到 Zookeeper 的 conf 目錄下。
export SERVER_JVMFLAGS="-Djava.security.auth.login.config=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/jaas.conf -Djava.security.krb5.conf=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/krb5.conf"
export CLIENT_JVMFLAGS="${CLIENT_JVMFLAGS} -Djava.security.auth.login.config=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/jaas.conf -Djava.security.krb5.conf=/home/hadoop/app/apache-zookeeper-3.6.3-bin/conf/krb5.conf -Dzookeeper.server.principal=zk-server/pxc1@ABC.COM" #這里不同的主機上,需修改為本機的主機名
SERVER_JVMFLAGS 是服務端(zkServer.sh)的配置
CLIENT_JVMFLAGS 是客戶端(zkClis.sh)的配置,zookeeper.server.principal 參數用於配置服務端 principal(默認為 zookeeper/localhost@{realm},可能不存在)
2.2.3、啟動並測試
配置完成后就可以啟動 Zookeeper 集群了:
bin/zkServer.sh start
啟動完成后可以使用 zkCli.sh 來測試:
bin/zkCli.sh
2.2.4、java 程序連接 Zookeeper
java 可以使用 JAAS 來進行 Kerberos 認證,需要 JAAS 配置文件、keytab 文件及 Kerberos 配置文件。
A、配置文件
JAAS 配置文件(zk-client-jaas.conf):
Client {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true keyTab="D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client.keytab" storeKey=true useTicketCache=false principal="zk-client@ABC.COM"; };
keytab 文件:
從 Kerberos 服務器上拷貝到目標機器,拷貝路徑即為 JAAS 配置中間配置的路徑:D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client.keytab。
Kerberos 配置文件(krb5.conf):
從 Kerberos 服務器上拷貝 /etc/krb5.conf 到目標機器即可。
B、配置 hosts 文件
在 hosts 文件中添加:
10.49.196.10 pxc1 10.49.196.11 pxc2 10.49.196.12 pxc3
C、引入依賴
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.3</version> </dependency>
D、樣例程序
package com.abc.demo.general.zookeeper; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; /** * Zookeeper 客戶端 Kerberos 認證 */ public class ZookeeperKerberosCase { /** * 使用ip訪問也可以:10.49.196.10:2181,10.49.196.11:2181,10.49.196.12:2181。 * 但 hosts 文件還是要配置的,Zookeeper 客戶端會查找 ip 對應的主機名作為 Zookeeper 服務的 principal 的 instance 部分, * 如果找不到對應的主機名就使用 ip 代替,這會導致找不到對應的 principal。 */ private static String connectString = "pxc1:2181,pxc2:2181,pxc3:2181"; private static int sessionTimeout = 200 * 1000; private ZooKeeper zooKeeper; @Before public void before() { System.setProperty("java.security.auth.login.config", "D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\zk-client-jaas.conf"); System.setProperty("java.security.krb5.conf", "D:\\workspaceidea\\demo\\demo\\src\\main\\resources\\kerberos\\krb5.conf");//Zookeeper 服務的 principal 的 primary 部分 System.setProperty("zookeeper.sasl.client.username", "zk-server"); try { zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override public void process(WatchedEvent watchedEvent) { } }); System.out.println(zooKeeper.getState()); } catch (IOException e) { e.printStackTrace(); } } @After public void after() throws Exception { zooKeeper.close(); } @Test public void getData() throws Exception { Stat stat = new Stat(); byte[] data = zooKeeper.getData("/javatest/node1", false, stat); System.out.println(new String(data)); System.out.println(stat); } }
3、Server-Server 的 Kerberos 認證
在主節點選舉階段,集群中的所有服務器都將參與以達到規定的票數;默認情況下,此通信不經過身份驗證。Zookeeper 也支持在集群的服務器之間啟用 Kerberos 認證,這里就不介紹了,詳細說明可參考官網文檔:https://cwiki.apache.org/confluence/display/ZOOKEEPER/Server-Server+mutual+authentication。