Kafka Kerberos 安全认证
阅读原文时间:2023年07月11日阅读:1

本主要介绍在 Kafka 中如何配置 Kerberos 认证,文中所使用到的软件版本:Java 1.8.0_261Kafka_2.12-2.6.0Kerberos 1.15.1

1. Kerberos 安装

要使用 Kerberos 服务,需先安装 Kerberos,安装方法可参考:Kerberos 安装及使用

2. Kafka 开启 Kerberos 认证

节点信息如下:

IP

主机名

描述

10.0.16.14

centos-01

zookeeper、kafka

2.1 创建 keytab

在安装 Kerberos 的机器上进入 kadmin(Kerberos 服务端上使用 kadmin.local,安装了 Kerberos Client 的机器上可以使用 kadmin),然后执行如下命令分别创建服务端和客户端的 keytab:

kadmin.local:  add_principal -randkey kafka-server/centos-01@ABC.COM
kadmin.local:  add_principal -randkey kafka-client@ABC.COM
kadmin.local:  xst -k /root/kafka-server.keytab kafka-server/centos-01@ABC.COM
kadmin.local:  xst -k /root/kafka-client.keytab kafka-client@ABC.COM

2.2 配置

2.2.1 配置 hosts 文件

10.0.16.14  centos-01

2.2.2 Kerberos 相关配置

拷贝 krb5.conf 及 keytab 文件到所有安装 Kafka 的机器,把文件都放到 Kafka 的 config/kerveros 目录下(kerberos 目录需新建)。

2.2.3 Kafka 服务端配置

复制 config/server.properties(复制动作能帮助我们在 认证/非认证 模式自由切换)重命名为 config/server-sasl.properties,增加如下配置:

listeners=SASL_PLAINTEXT://centos-01:9092
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=GSSAPI
sasl.enabled.mechanisms=GSSAPI
sasl.kerberos.service.name=kafka-server

新建 kafka-server-jaas.conf 文件,该文件也放到 Kafka 的 config/kerveros 目录下:

KafkaServer {
   com.sun.security.auth.module.Krb5LoginModule required
   useKeyTab=true
   keyTab="/data/kafka_2.12-2.6.0/config/kerberos/kafka-server.keytab"
   storeKey=true
   useTicketCache=false
   principal="kafka-server/centos-01@ABC.COM";
};

复制 bin/kafka-server-start.sh 脚本重命名为 bin/kafka-server-start-sasl.sh,倒数第二行增加如下配置:

export KAFKA_OPTS="-Dzookeeper.sasl.client=false -Dzookeeper.sasl.client.username=zk-server -Djava.security.krb5.conf=/data/kafka_2.12-2.6.0/config/kerberos/krb5.conf -Djava.security.auth.login.config=/data/kafka_2.12-2.6.0/config/kerberos/kafka-server-jaas.conf"

2.2.4 Kafka 客户端配置

该配置主要为了使用 bin/kafka-topics.sh、bin/kafka-console-consumer.sh、kafka-console-producer.sh 等命令。

新建 client.properties 文件,该文件也放到 Kafka 的 config/kerveros 目录下:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=GSSAPI
sasl.kerberos.service.name=kafka-server

新建 kafka-client-jaas.conf 文件,该文件也放到 Kafka 的 config/kerveros 目录下:

KafkaClient {
   com.sun.security.auth.module.Krb5LoginModule required
   useKeyTab=true
   keyTab="/data/kafka_2.12-2.6.0/config/kerberos/kafka-client.keytab"
   storeKey=true
   useTicketCache=false
   principal="kafka-client@ABC.COM";
};

复制 bin/kafka-topics.sh、kafka-console-producer.sh、bin/kafka-console-consumer.sh 脚本,分别重命名为 bin/kafka-topics-sasl.shkafka-console-producer-sasl.shbin/kafka-console-consumer-sasl.sh,倒数第二行增加如下配置:

export KAFKA_OPTS="-Djava.security.krb5.conf=/data/kafka_2.12-2.6.0/config/kerberos/krb5.conf -Djava.security.auth.login.config=/data/kafka_2.12-2.6.0/config/kerberos/kafka-client-jaas.conf"

2.3 启动测试

运行 bin/kafka-server-start-sasl.s 启动 Kafka 集群:

cd /data/kafka_2.12-2.6.0
./bin/kafka-server-start-sasl.sh -daemon config/server-sasl.properties

运行 bin/kafka-topics-sasl.sh 查看 topic 列表信息:

./bin/kafka-topics-sasl.sh --list --bootstrap-server 10.0.16.14:9092 --command-config config/kerberos/client.properties

运行 kafka-console-producer-sasl.sh 生产消息:

./bin/kafka-console-producer-sasl.sh --broker-list 10.0.16.14:9092 --topic test --producer.config config/kerberos/client.properties

运行 bin/kafka-console-consumer-sasl.sh 消费消息:

./bin/kafka-console-consumer-sasl.sh --bootstrap-server 10.0.16.14:9092 --topic test --from-beginning --consumer.config config/kerberos/client.properties

2.4 java 程序连接 Kafka

java 可以使用 JAAS 来进行 Kerberos 认证,需要 JAAS 配置文件、keytab 文件及 Kerberos 配置文件。

2.4.1 配置文件

  • JAAS 配置文件(kafka-client-jaas.conf):

    KafkaClient {
       com.sun.security.auth.module.Krb5LoginModule required
       useKeyTab=true
       keyTab="F:\\JavaWorkspace\\kafka\\src\\main\\resources\\kafka-client.keytab"
       storeKey=true
       useTicketCache=false
       principal="kafka-client@ABC.COM";
    };
  • keytab 文件:

    从 Kerberos 服务器上拷贝到目标机器,拷贝路径即为 JAAS 配置文件中配置的路径:F:\\JavaWorkspace\\kafka\\src\\main\\resources\\kafka-client.keytab

  • Kerberos 配置文件(krb5.conf):

    从 Kerberos 服务器上拷贝 /etc/krb5.conf 到目标机器即可。

2.4.2 配置 hosts 文件

C:\Windows\System32\drivers\etc\hosts 文件中添加:

10.0.16.14  centos-01

2.4.3 引入依赖

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.12</artifactId>
    <version>2.6.0</version>
</dependency>

2.4.4 样例程序

package kafka;

import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

public class TestKafkaKerberos {

    public static void main(String[] args) {
        System.setProperty("java.security.auth.login.config",
                "F:\\JavaWorkspace\\kafka\\src\\main\\resources\\kafka-client-jaas.conf");
        System.setProperty("java.security.krb5.conf", "F:\\JavaWorkspace\\kafka\\src\\main\\resources\\krb5.conf");

        Properties props = new Properties();
        props.put("bootstrap.servers", "10.0.16.14:9092");
        props.put("group.id", "test_group");
        props.put("enable.auto.commit", "true");
        props.put("auto.commit.interval.ms", "1000");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        // sasl
        props.put("sasl.mechanism", "GSSAPI");
        props.put("security.protocol", "SASL_PLAINTEXT");
        props.put("sasl.kerberos.service.name", "kafka-server");

        @SuppressWarnings("resource")
        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);
        String topic = "test";
        consumer.subscribe(Arrays.asList(topic));
        while (true) {
            try {
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
                for (ConsumerRecord<String, String> record : records) {
                    System.out.printf("offset = %d, partition = %d, key = %s, value = %s%n",
                            record.offset(), record.partition(), record.key(), record.value());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

实际上,样例程序中的种种设置就是为了还原我们在上一步中改动 bin/kafka-console-consumer-sasl.sh + config/kerberos/client.properties 的过程,二者是对应的:

3. 常见问题

  1. Caused by: javax.security.auth.login.LoginException: Could not login: the client is being asked for a password...

    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 com.sun.security.auth.module.Krb5LoginModule.promptForPass(Krb5LoginModule.java:944)
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:764)
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
        at 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:112)
        at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:158)
        ... 7 more

    报错原因是 keytab 文件不正确,可能是 principle 不匹配或其它配置文件错误。本文中所犯错误是,Windows 的路径要写双斜线,否则配置文件无法正确读取。

  2. KrbException: Server not found in Kerberos database

    报错的可能原因之一是未配置 hosts 文件。认证策略中肯能会使用缓存,配置了 hosts 文件后要重启 IDE。

    Caused by: GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - LOOKING_UP_SERVER)
        at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:772)
        at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
        at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
        at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:192)
        ... 20 more
    Caused by: KrbException: Server not found in Kerberos database (7) - LOOKING_UP_SERVER
        at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:73)
        at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:251)
        at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:262)
        at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:308)
        at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:126)
        at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:466)
        at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:695)
        ... 23 more
    Caused by: KrbException: Identifier doesn't match expected value (906)
        at sun.security.krb5.internal.KDCRep.init(KDCRep.java:140)
        at sun.security.krb5.internal.TGSRep.init(TGSRep.java:65)
        at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:60)
        at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:55)
        ... 29 more

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器