目录
Kerbeos简介
Kerbeos认证流程
Kerberos安装步骤
kerberos简单操作
Kafka集成Kerberos例子
本地环境java客户端消费测试代码
错误记录
Kerberos可以将认证的密钥在集群部署时事先放到可靠的节点上。集群运行时,集群内的节点使用密钥得到认证,认证通过后的节点才能提供服务。企图冒充的节点由于没有事先得到的密钥信息,无法与集群内部的节点通信。这样就防止了恶意地使用或篡改Hadoop集群的问题,确保了Hadoop集群的可靠性、安全性。
1、client发送请求AS,AS验证DB是否存在该用户,存在即返回两个消息A和B
消息A:Client和TGS通信的会话秘钥,该消息通过用户秘钥进行加密
消息B:票据授权票据(TGT),内容包含消息A中Client/TGS的会话秘钥、用户ID、用户网址、TGT有效期,该消息通过TGS密码进行加密
注意:用户不向AS发送“用户密钥”(user's secret key),也不发送密码,AS能够从本地数据库查到申请用户的密码,并通过转换得到用户秘钥
2、client收到两个返回消息,首先尝试用自己秘钥解密消息A,如果用户输入的密码与AS数据库中的密码不符,则不能成功解密消息A。
正确即得到Client/TGS的会话秘钥。
注意:Client不能解密消息B,因为消息B是用TGS秘钥加密的,有了Client/TGS会话秘钥,Client就足以TGS进行认证了。
1、Client需要申请特定服务时,向TGS发送两个消息C和D
消息C:消息B的内容和想获取的服务ID(不是用户ID)
消息D:认证符Authenticator(包括:用户ID,时间戳),通过Client/TGS会话密钥进行加密。
2、TGS收到消息C和D,首先检查KDC数据库中是否存在所需服务,然后用自己的秘钥解密消息B(TGT),从而得到Client/TGS会话秘钥,
TGS再用这个秘钥解密消息D得到用户ID和时间戳,并对TGT和Authenticator进行验证,通过后返回两条消息E和F
消息E:Client-server票据(包括Client/SS的会话密钥,用户ID,用户网址,有效期),通过服务器秘钥进行加密
消息F:Client/SS会话密钥,用在将来Client和SS通信,通过Client/TGS进行加密
3、Client收到消息E和F后,用Client/TGS会话秘钥解密消息F,得到Client/SS会话秘钥
注意:Client不能解密消息E,因为E是用“服务器密钥”(service's secret key)加密的
1、获得Client/SS会话密钥之后, Client就能够使用服务器提供的服务了。Client向指定服务器SS发出2条消息G和H
消息G:即上一步消息E,通过服务器秘钥加密
消息H:即新的Authenticator(包括用户ID,时间戳),通过Client/SS会话秘钥进行加密
2、SS用自己的秘钥解密消息G从而得到Client/SS会话秘钥,再用这个秘钥解密消息H得到Authenticator,对Ticket和
Authenticator进行验证,通过即返回消息I(确认身份成功,乐于提供服务)
消息I:新时间戳(Client发送的时间戳+1),通过Client/SS会话秘钥加密
3、Client通过Client/SS解密,得到新时间戳并验证,通过则信赖服务器,并向服务器发送服务请求
4、服务器向客户端提供相应的服务
yum install krb5-server krb5-libs krb5-workstation -y
vim /var/kerberos/krb5kdc/kdc.conf
内容如下:
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
[realms]
HADOOP.COM = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
max_renewable_life = 7d
supported_enctypes = aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}
vim /etc/krb5.conf
内容如下:
# Configuration snippets may be placed in this directory as well
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = HADOOP.COM
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
clockskew = 120
udp_preference_limit = 1
[realms]
HADOOP.COM = {
kdc = es1 //改为服务器主机名
admin_server = es1 //改为服务器主机名
}
[domain_realm]
.hadoop.com = HADOOP.COM
hadoop.com = HADOOP.COM
kdb5_util create -s -r HADOOP.COM
vim /var/kerberos/krb5kdc/kadm5.acl
#修改如下
*/[email protected] *
systemctl start kadmin krb5kdc
systemctl enable kadmin krb5kdc
kadmin.local
listprincs
addprinc kafka/es1
change_password kafka/es1
delete_principal kafka/es1
?
exit
1、生成用户keytab(该文件后续kafka配置和客户端认证需用到)
kadmin.local -q "xst -k /var/kerberos/krb5kdc/kadm5.keytab kafka/[email protected]"
注意:生成keytab后,密码被修改了,无法再用之前密码登陆
不改变密码的方法:
kadmin.local
xst -k kadmin.keytab -norandkey kafka/[email protected]
2、在kafka安装目录下config创建kafka-jaas.conf
KafkaServer {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
storeKey=true
keyTab="/var/kerberos/krb5kdc/kadm5.keytab"
principal="kafka/[email protected]";
};
KafkaClient {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
useTicketCache=true
keyTab="/var/kerberos/krb5kdc/kadm5.keytab"
principal="kafka/[email protected]";
};
3、在config/server.properties添加如下配置
advertised.listeners=SASL_PLAINTEXT://es1:9092
listeners=SASL_PLAINTEXT://es1:9092
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=GSSAPI
sasl.enabled.mechanisms=GSSAPI
sasl.kerberos.service.name=kafka
4、在bin/kafka-run-class.sh脚本添加kafka jvm参数(下划线部分内容)
#jvm performance options
if [ -z "$KAFKAJVMPERFORMANCEOPTS" ]; then KAFKAJVMPERFORMANCEOPTS="-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ExplicitGCInvokesConcurrent -Djava.awt.headless=true -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/home/xingtongping/kafka_2.12-2.2.0/config/kafka-jaas.conf" fi
5、配置config/producer.properties,kafka生产者kerberos配置
security.protocol = SASL_PLAINTEXT
sasl.mechanism = GSSAPI
sasl.kerberos.service.name =kafka
6、配置config/consumer.properties,kafka消费者kerberos配置
security.protocol = SASL_PLAINTEXT
sasl.mechanism = GSSAPI
sasl.kerberos.service.name=kafka
启动kafka服务
bin/kafka-server-start.sh config/server.properties
生产者
bin/kafka-console-producer.sh --broker-list es1:9092 --topic test --producer.config config/producer.properties
消费者
bin/kafka-console-consumer.sh --bootstrap-server es1:9092 --topic test --consumer.config config/consumer.properties
注意:
1、把krb5.conf和kafka-jaas.conf下载到本地,并且修改kafka-jaas.conf文件的keytab路径:改为本地keytab路径
2、使用域名记得修改hosts文件,添加内容:172.16.110.173 es1
public class Consumer {
public static void main(String[] args) throws IOException {
System.setProperty("java.security.krb5.conf","C:/Users/Administrator/Downloads/krb5.conf"); //认证代码
System.setProperty("java.security.auth.login.config","C:/Users/Administrator/Downloads/kafka-jaas.conf");//认证代码
Properties props = new Properties();
//集群地址,多个地址用","分隔
props.put("bootstrap.servers", "es1:9092");
props.put("sasl.kerberos.service.name", "kafka"); //认证代码
props.put("sasl.mechanism", "GSSAPI"); //认证代码
props.put("security.protocol", "SASL_PLAINTEXT"); //认证代码
props.put("group.id", "1");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//创建消费者
KafkaConsumer consumer = new KafkaConsumer(props);
// 订阅topic,可以为多个用,隔开,此处订阅了"test"这个主题
consumer.subscribe(Arrays.asList("test"));
//持续监听
while(true){
//poll频率
ConsumerRecords consumerRecords = consumer.poll(100);
for(ConsumerRecord consumerRecord : consumerRecords){
System.out.println("在test中读到:" + consumerRecord.value());
}
}
}
}
我在用linux命令启动消费者的时候出现,如图所示
解决办法: 这个问题是因为我没有在kafka-jaas.conf中添加KafkaClient配置,所以在kafka-jaas.conf添加配置就解决了 #内容如下 KafkaClient { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true useTicketCache=true keyTab="/var/kerberos/krb5kdc/kadm5.keytab" principal="kafka/[email protected]"; };
解决了问题一后,我继续用linux命令启动消费者,结果出现如图所示错误,启动命令如下
bin/kafka-console-consumer.sh --bootstrap-server 172.16.110.173:9092 --topic test --consumer.config config/consumer.properties
解决办法: 看错误信息可看出,提示说在kerberos数据库中找不到服务器,困扰了很久,后来我把启动命令改为如下即成功了,即把ip改为域名,
可能服务器向kerberos注册时候使用了es1,我猜想跟krb5.conf文件配置中有关,改文件且需初始化数据库(猜想) 使用下面命令启动: bin/kafka-console-consumer.sh --bootstrap-server es1:9092 --topic test --consumer.config config/consumer.properties
启动生产者或者消费者时候没有认证通过的时候,貌似kafka服务端就会一直出现图中信息,如kafka集成了kerberos,但是java客户端仍然用原来没有认证的代码访问。
本地使用java代码消费的时候出现,如图所示
解决办法: 把下载的kafka-jaas.conf中keytab路径改为本地路径即可
本地使用java代码消费的时候出现,如图所示
解决办法: 把错误信息百度翻译了一波,Clock skew too great,时钟偏差太大,于是我看了看服务器时间和本地时间,相差了5分钟,我把本地事件调整下,最终完成了。
安装完kerberos,使用kinit登陆时出现报错
解决办法:
检查/etc/krb5.conf文件中realms配置主机是否正确
HADOOP.COM = {
kdc = es1
admin_server = es1
}
后来为了验证文章正确,又用一台服务器重新装了一遍,发现了一些问题。
注意:
1、创建kerberos的用户时候,命名格式感觉要规范
服务名/主机名
如服务名为kafka,主机名为es1
即命名为kafka/es1
在server.properties、consumer.properties、producer.properties等文件都要用到服务名,即kafka
2、别忘了修改/etc/hosts文件做域名映射哦
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.17.196.210 xtp
3、如果之前已经初始化过一次数据库,后来需要修改krb5.conf内容,如服务器名字变了,在运行时遇到错误说server不在kerberos的数据库中,这时候可能需要重新初始化这个realm,步骤如下:
1、删除krb5kdc目录下的principal开头的文件
命令:rm -rf /var/kerberos/krb5kdc/principal*
2、初始化kerberos database
命令:kdb5_util create -s -r HADOOP.COM
2019-05-29更新:
问题记录:
集群:spark01 、spark02 、spark03
搭建集群的时候,kafka-jaas.conf配置文件的kafkaServer我统一使用了kafka/spark01用户,结果搭建起来创建topic,查看topic都正常,但是生产者不能生产消息,消费者不能消费消息,出现了各种各样的错误。
生产者发送消息时:
后来在启动kafka的日志中发现不太一样,spark01的日志会全一点,包含很多group metadata等字眼的日志信息,spark02和spark03看起来正常启动了,但是缺少了这部分日志,我觉得集群有问题,我猜想是因为统一使用了kafka/spark01的用户问题,因为只有spark01节点启动日志完整,于是给各个节点使用不同的用户,如spark02使用kafka/spark02的配置,最终启动日志正常,生产者和消费者也正常