升级JDK17后InternalKafkaListenerEndpointRegistry Bean启动失败排查
JDK17+Gradle7.3升级后Kafka Kerberos认证失败(RC4-HMAC-NT兼容问题)
将项目JDK从11升级至17、Gradle从7.0.2升级至7.3后,启动应用时出现InternalKafkaListenerEndpointRegistry Bean启动失败的错误,根源为Kafka消费者构建时触发Kerberos认证异常。回退至旧版本JDK和Gradle时应用可正常运行。
已确认问题是JDK17弃用了RC4-HMAC-NT加密的keytab,将keytab加密方式改为-crypto ALL后应用恢复,但希望从Java服务端层面找到RC4-HMAC-NT的向后兼容方案。
报错日志
2024-03-12 18:08:44,822 [main] - Application run failed org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.kafka.config.internalKafkaListenerEndpointRegistry'; nested exception is org.apache.kafka.common.KafkaException: Failed to construct kafka consumer at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) at java.base/java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) at some.SomeApplication.main(SomeApplication.java:12) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) Caused by: org.apache.kafka.common.KafkaException: Failed to construct kafka consumer at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:823) at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:632) at org.springframework.kafka.core.DefaultKafkaConsumerFactory.createRawConsumer(DefaultKafkaConsumerFactory.java:358) at org.springframework.kafka.core.DefaultKafkaConsumerFactory.createKafkaConsumer(DefaultKafkaConsumerFactory.java:326) at org.springframework.kafka.core.DefaultKafkaConsumerFactory.createConsumerWithAdjustedProperties(DefaultKafkaConsumerFactory.java:302) at org.springframework.kafka.core.DefaultKafkaConsumerFactory.createKafkaConsumer(DefaultKafkaConsumerFactory.java:269) at org.springframework.kafka.core.DefaultKafkaConsumerFactory.createConsumer(DefaultKafkaConsumerFactory.java:243) at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.<init>(KafkaMessageListenerContainer.java:639) at org.springframework.kafka.listener.KafkaMessageListenerContainer.doStart(KafkaMessageListenerContainer.java:305) at org.springframework.kafka.listener.AbstractMessageListenerContainer.start(AbstractMessageListenerContainer.java:338) at org.springframework.kafka.listener.ConcurrentMessageListenerContainer.doStart(ConcurrentMessageListenerContainer.java:204) at org.springframework.kafka.listener.AbstractMessageListenerContainer.start(AbstractMessageListenerContainer.java:338) at org.springframework.kafka.config.KafkaListenerEndpointRegistry.startIfNecessary(KafkaListenerEndpointRegistry.java:312) at org.springframework.kafka.config.KafkaListenerEndpointRegistry.start(KafkaListenerEndpointRegistry.java:257) at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ... 23 common frames omitted Caused by: org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: Could not login: the client is being asked for a password, but the Kafka client code does not currently support obtaining a password from the user. not available to garner authentication information from the user at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:172) at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:157) at org.apache.kafka.common.network.ChannelBuilders.clientChannelBuilder(ChannelBuilders.java:73) at org.apache.kafka.clients.ClientUtils.createChannelBuilder(ClientUtils.java:105) at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:740) ... 37 common frames omitted Caused by: javax.security.auth.login.LoginException: Could not login: the client is being asked for a password, but the Kafka client code does not currently support obtaining a password from the user. not available to garner authentication information from the user at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.promptForPass(Krb5LoginModule.java:925) at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:745) at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:597) at java.base/javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:679) at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:677) at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) at java.base/javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:677) at java.base/javax.security.auth.login.LoginContext.login(LoginContext.java:587) at org.apache.kafka.common.security.authenticator.AbstractLogin.login(AbstractLogin.java:60) at org.apache.kafka.common.security.kerberos.KerberosLogin.login(KerberosLogin.java:103) at org.apache.kafka.common.security.authenticator.LoginManager.<init>(LoginManager.java:62) at org.apache.kafka.common.security.authenticator.LoginManager.acquireLoginManager(LoginManager.java:105) at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:158) ... 41 common frames omitted
JAAS配置
@Component @Setter @Getter @ConditionalOnProperty(value = "kafka.etl.enabled", havingValue = "true", matchIfMissing = true) class KafkaEtlProperties { private static final String SECURITY_PROTOCOL = "security.protocol"; private static final String SASL_MECHANISM = "sasl.mechanism"; private static final String SASL_KERBEROS_SERVICE_NAME = "sasl.kerberos.service.name"; private static final String SASL_JAAS_CONFIG = "sasl.jaas.config"; private final Map<String, String> props; public KafkaEtlProperties(@Value("${kafka.etl.principal:${spring.datasource.username}}") String principal) { props = new HashMap<>(); props.put(SECURITY_PROTOCOL, "SASL_PLAINTEXT"); props.put(SASL_MECHANISM, "GSSAPI"); props.put(SASL_KERBEROS_SERVICE_NAME, "kafka"); props.put(SASL_JAAS_CONFIG, """ com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab="/kerberos/keytab" principal="%s"; """.formatted(principal)); } }
项目build.gradle配置
buildscript { ext { springBootVersion = '2.4.5' } repositories { mavenLocal() mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' sourceCompatibility = JavaVersion.VERSION_17 jar { enabled = true } dependencies { implementation group: 'org.springframework.kafka', name: 'spring-kafka' implementation project(":some-core") implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.flywaydb:flyway-core' implementation 'org.apache.commons:commons-lang3' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' compileOnly 'org.projectlombok:lombok' implementation 'org.reflections:reflections:0.9.10' implementation 'org.postgresql:postgresql' testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude group: "org.junit.vintage", module: "junit-vintage-engine" } testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' testImplementation 'org.mockito:mockito-junit-jupiter:2.23.4' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' testImplementation("org.junit.jupiter:junit-jupiter-params:5.4.2") annotationProcessor 'org.projectlombok:lombok' }
some-core模块build.gradle配置
buildscript { ext { springBootVersion = '2.4.5' } repositories { mavenLocal() mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' sourceCompatibility = JavaVersion.VERSION_17 jar { enabled = true } bootJar { enabled = false } dependencies { implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'org.springframework.boot:spring-boot-starter-cache' implementation 'org.springframework:spring-context-support' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.kafka:spring-kafka' implementation 'com.github.ben-manes.caffeine:caffeine' implementation 'org.hibernate.validator:hibernate-validator-annotation-processor' implementation 'org.hibernate.validator:hibernate-validator' implementation 'org.hibernate:hibernate-entitymanager' implementation 'org.flywaydb:flyway-core' compileOnly 'javax.validation:validation-api' implementation 'org.reflections:reflections:0.9.10' implementation 'org.apache.commons:commons-lang3' implementation 'com.fasterxml.jackson.core:jackson-core' implementation 'com.fasterxml.jackson.core:jackson-annotations' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '3.9' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'org.postgresql:postgresql' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' implementation group: 'com.google.guava', name: 'guava', version: '27.0.1-jre' implementation group: 'org.apache.commons', name: 'commons-csv', version: '1.6' annotationProcessor 'org.hibernate:hibernate-jpamodelgen:5.4.9.Final' implementation 'com.vladmihalcea:hibernate-types-52:2.9.8' testImplementation 'org.junit.jupiter:junit-jupiter-api' testImplementation 'org.mockito:mockito-junit-jupiter' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' testImplementation 'org.junit.jupiter:junit-jupiter-params' }
已知临时解决方案与疑问
已确认问题根源是JDK17中弃用了RC4-HMAC-NT加密算法的keytab,将keytab生成时的加密方式改为-crypto ALL后,应用可正常启动。但希望找到Java服务端层面的向后兼容方案,无需修改keytab即可适配JDK17的环境。
内容的提问来源于stack exchange,提问作者chshaem
相关产品推荐
相关产品推荐

