Kafka-Kerberos票据刷新问题

        线上kafka使用了 kerberos 认证,每隔24小时,票据过期,无法自动续期,出现消息发送失败问题。

        从日志可以发现会有如下报错:

2023-09-14 17:48:47,144 [kafka-kerberos-refresh-thread-kafka/[email protected]] [] WARN  [o.a.kafka.common.security.kerberos.KerberosLogin] KerberosLogin.java:216 - [Principal=kafka/[email protected]]: Error when trying to renew with TicketCache, but will retry 
java.io.IOException: Cannot run program "/usr/bin/kinit": CreateProcess error=2, 系统找不到指定的文件。
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128)
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071)
	at org.apache.kafka.common.utils.Shell.runCommand(Shell.java:85)
	at org.apache.kafka.common.utils.Shell.run(Shell.java:76)
	at org.apache.kafka.common.utils.Shell$ShellCommandExecutor.execute(Shell.java:204)
	at org.apache.kafka.common.utils.Shell.execCommand(Shell.java:268)
	at org.apache.kafka.common.utils.Shell.execCommand(Shell.java:255)
	at org.apache.kafka.common.security.kerberos.KerberosLogin.lambda$login$0(KerberosLogin.java:212)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.io.IOException: CreateProcess error=2, 系统找不到指定的文件。
	at java.base/java.lang.ProcessImpl.create(Native Method)
	at java.base/java.lang.ProcessImpl.(ProcessImpl.java:492)
	at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:153)
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1107)
	... 8 common frames omitted

        由于线上系统日志输出比较多,也并没有对warn级别日志做单独的过滤,所以最初并没有发现这个提示。从报错信息看,相关业务逻辑是在 KerberosLogin 类中。

        其实每次启动项目(springboot+kakfa),KerberosLogin 会初始化 kerberos 认证过程,如下图:

Kafka-Kerberos票据刷新问题_第1张图片

yml文件相关配置:

spring:
  application:
    name: kerberos
  kafka:
    consumer:
      bootstrap-servers: hdp-1:6667,hdp-2:6667,hdp-3:6667
      group-id: kafka-example
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      enable-auto-commit: true
      auto-commit-interval: 1000
      auto-offset-reset: earliest
    producer:
      bootstrap-servers: hdp-1:6667,hdp-2:6667,hdp-3:6667
      acks: -1
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    security:
      protocol: SASL_PLAINTEXT
    jaas:
      enabled: true
      login-module: com.sun.security.auth.module.Krb5LoginModule
      options:
        useKeyTab: true
        storeKey: true
        useTicketCache: false
        keyTab: file:D:/code/kerberos/kafka.keytab
        principal: kafka/[email protected]
    properties:
      sasl:
        mechanism: GSSAPI
        kerberos:
          service:
            name: kafka
          min:
            time:
              before:
                relogin: 1

        查看 KerberosLogin 源码,isUsingTicketCache (是否使用票据缓存),对应配置中的useTicketCache:

Kafka-Kerberos票据刷新问题_第2张图片

如果 useTicketCache 设置成 true,会经过如下逻辑:

Kafka-Kerberos票据刷新问题_第3张图片

tips: 如果大家查看源码的话,可以关注一下 KerberosLogin 的 login 方法,此方法创建了一个 定时任务的线程,用来解决票据刷新问题的,具体代码我就不贴图啦。

 此方法会调用 shell 命令:

Kafka-Kerberos票据刷新问题_第4张图片

 后续有查看了kafka的官方文档,发现有相关的配置项:

Kafka-Kerberos票据刷新问题_第5张图片

文档链接:Kafka 中文文档 - ApacheCNApache Kafka: A Distributed Streaming Platform.icon-default.png?t=N7T8https://kafka.apachecn.org/documentation.html#producerconfigs

 

        至此找到了问题出现的原因,由于线上项目 useTicketCache 设置成了 true, 导致每次票据刷新的定时任务都会经过上述逻辑,调用 Kerberos kinit 命令,但是项目运行的服务器并没有 kinit,所以出现异常,票据刷新失败。

你可能感兴趣的:(kafka,kerberos)