前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kafka之ranger插件的一个坑

kafka之ranger插件的一个坑

作者头像
陈猿解码
发布2023-02-28 15:12:47
7270
发布2023-02-28 15:12:47
举报
文章被收录于专栏:陈猿解码陈猿解码

之前文章写过kafka的鉴权,以及集成ranger插件的配置使用。但真正在用起来后,发现里面有个坑,本文就来聊聊这个坑的情况以及排查过程。

【问题现象】

kafka在集成了ranger插件实现鉴权功能后,发现过一段时间后,controller无法正确连接上broker,并有如下报错:

代码语言:javascript
复制
// server.log中的日志
[2022-12-06 15:32:48,068] ERROR [Controller id=0, targetBrokerId=0] Connection to node 0 failed authentication due to: Authentication failed due to invalid credentials with SASL mechanism GSSAPI (org.apache.kafka.clients.NetworkClient)
// controller.log中的日志
[2022-12-06 15:32:48,663] WARN [RequestSendThread controllerId=0] Controller 0's connection to broker kafka-0.bigdata:9090 (id: 0 rack: null) was unsuccessful (kafka.controller.RequestSendThread)

【问题分析】

1. 初步分析

问题咋一看,稍微有点懵,跑得好好的怎么突然就报错了。从日志也不太能看出问题产生的前后逻辑。所以先花了些时间整理相关的逻辑流程、涉及的类以及彼此之间的关系。

1)在kafka的controller管理中,维护了一个broker信息的hashmap,其ID为broker的ID,broker信息则以ControllerBrokerStateInfo实例对象记录。

2)每个ControllerBrokerStateInfo内部都有一个队列,controller需要给broker的发送的请求,均直接发送到该队列中;除了队列,每个ControllerBrokerStateInfo还有一个请求发送线程,循环从队列中取出消息发送给对应的broker。而network则记录与该broker的网络连接相关信息。

3) ControllerBrokerStateInfo中的network,往下细分,又包含Selector、KafkaChannel、ChannelBuilder、TransportLayer、Authenticator这么几层。

Selector:充当IO轮询处理的衔接,内部为不同broker,封装为不同的KafkaChannel。

ChannelBuilder:这是一个接口,具体有不同的实现,实际会根据配置中指定的协议类型(SASL、SSL、Plaintext)构造对应的实例类对象。该channelBuilder后续会再根据指定的模式(客户端或服务端)创建对应的传输层(TransportLayer)和鉴权(Authenticator)。

TransportLayer:也是一个接口,会根据实际的协议构造对应的实例类对象,负责完成请求与响应数据的传输

Authenticator:同样是一个接口,根据协议类型构造对应的实例类对象,完成交互过程中可能需要的鉴权,对于SASL又会区分客户端和服务端

KafkaChannel:对应一个broker的连接信息,内部有TransportLayer、Authenticator的实例对象作为类成员,记录连接相关的信息。

对于开启kafka鉴权时,配置采用了SASL_PLAINTEXT的协议,同时在jaas中指定了keytab文件与对应的principal。

那么controller在与broker交互过程中,会根据协议类型使用SaslChannelBuilder,同时读取jaas配置文件中的principal,并将其传递给SaslClientAuthenticator、SaslServerAuthenticator,在内部分别构造SaslClient、SaslServer时也会透传该principal信息。

2. 锁定问题出现场景

初步梳理了整个流程后,未发现存在问题的地方,也没搞清楚问题出现的时机。于是只能改变思路,模拟制造一些异常场景来分析可能出现问题的时机。

通过制造与zookeeper之间的网络异常、与kerberos之间的网络异常、进程重启、断电等场景来尝试复现问题,但问题就是没有出现。

感觉再次陷入死胡同时,中途插入另外一个紧急的事情,于是将环境搁置了一天,等忙完紧急事情后,发现问题复现了。联想到我们的kerberos票据有效期恰好是1天时间,于是尝试手动缩短kdc的票据时间来加速问题复现,当票据过期后,惊喜地发现问题复现了。

也就是说, 在kerberos票据过期后,尤其是触发controller重新选举,会立即出现该问题。

那么,在这种情形下,前一个版本是否也有同样的问题呢?

回退到前一个版本,再次执行同样的步骤尝试复现,但此时新的controller都能正确的连接到broker。

这也就说明只有当前版本存在这个问题。而当前版本的改动点主要就是引入的ranger插件实现kafka的权限控制。

通过尝试关闭kafka的鉴权、以及使用kafka原生自带的鉴权方式来再次复现问题时,结果都正常。

这样,也就真正锁定了方向,该问题就是使用ranger的kafka插件后,在kerberos票据过期后,必然出现新的controller与所有broker均连接失败的问题。

3. 再次分析

确定问题出现的场景后,终于可以有的放矢进行分析了,重新复现问题后,先通过arthas对错误打印对应代码处进行了跟踪,发现和正常情况下的值有所不同(代码如下所示)

代码语言:javascript
复制
// Jdk中的GssKrb5Server.java
public byte[] evaluateResponse(byte[] responseData) throws SaslException {
    ...
    if (protocolSaved != null &&
        !protocolSaved.equalsIgnoreCase(me.split("[/@]")[0])) {
        throw new SaslException(
            "GSS context targ name protocol error: " + me);
    }
    ...
}

正常情况下"protocolSaved"应该是一个空值,而出现问题时却是"hadoop"。

一开始怀疑是kafka所使用的keytab文件的问题(该文件中包含了两个principal,一个是kafka所使用的principal: kafka/_<HOSTNAME@bigdata.com>,另外一个则是hadoop),手动将keytab中hadoop的principal剔除后,发现出现问题时对应的值依旧是hadoop。

又一次查看整个流程,也没有看到有可能将hadoop赋值进去的地方,分析再一次陷入僵局。

再次转变思路,既然问题是引入ranger插件后引发的,先分析下ranger插件里面都做了些什么事情。

在ranger插件初始化时,会根据kafka中jaas指定的principal构造一个UGI(hadoop中的UserGroupInformation类),后续都会使用该UGI完成审计信息的记录。

但是:在构造UGI的时候,会在原有的subject中添加进程启动的系统用户的principal(对于我们的场景而言,kafka就是以hadoop用户来启动的。hadoop也就是在此时添加进去的)

这样一来,在subject中就同时增加了两个principal。

注意,subject中的首个principal还是jaas中指定的,因为是先依次构造的subject,然后在构造UGI时,才添加了进程对应系统用户的principal。

当kerberos票据过期后,keytab中对应的principal会从subject中移除,系统用户对应的principan会变成subject中的首个principal。

此后,kafka的controller连接broker的交互过程中,broker作为服务端创建saslServer时,由于subject中的首个principal已经变为系统用户,与客户端指定的服务端principal不符,导致出现问题。

【问题解决】

问题出现后,先在社区上逛了一圈,恰好发现有人已经修复了此问题,本质上就是在ranger插件中,修改调用UGI的方法,避免在原有subject中引入进程对应系统用户的principal。我们引入该patch后,问题也就自然而然地解决了。

对应的issue: https://issues.apache.org/jira/browse/RANGER-2810

【总结】

在这个问题排查过程中,有很多东西还可以再深入下,例如controller与broker交互的源码,jaas的原理等等,有兴趣的可以自己去看看。另外就是,遇到问题,先不要慌,偶现问题找规律变成必现问题,这样离解决问题就不远了。最后,开源的问题很多时候可以去社区上找找答案。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陈猿解码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档