Kafka配置SASL身份认证及权限实现文档

来源:互联网 发布:亿捷数据管家 编辑:程序博客网 时间:2024/06/05 00:34

一、 版本说明本例使用:zookeeper-3.4.10,kafka_2.11-0.11.0.0。zookeeper版本无要求,kafka必须使用0.8以后的版本

二、 zookeeper配置SASLzookeeper集群或者单节点配置相同。具体步骤如下:

1、zoo.cfg文件配置添加如下配置:

authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider

requireClientAuthScheme=sasl

jaasLoginRenew=3600000

2、编写JAAS文件这个文件定义需要链接到Zookeeper服务器的用户名和密码。

JAAS配置节默认为Server:

Server { 

org.apache.kafka.common.security.plain.PlainLoginModule required 

username="admin" 

password="admin-secret" 

user_kafka="kafka-sec" 

user_producer="prod-sec";

};

配置文件我命名为zk_server_jaas.conf,并放在部署目录的/usr/zookeeper/zookeeper-3.4.10/conf/下。文件中定义了身份认证类(org.apache.kafka.common.security.plain.PlainLoginModule),可以看到这个认证类是kafka命名空间,也就是需要加入kafka的插件,所以下面一步非常重要。这个文件中定义了两个用户,一个是kafka,一个是producer(user_可以定义多个用户,等于的值就是用户密码),这些用user_配置出来的用户都可以提供给生产者程序和消费者程序认证使用。还有两个属性,username和password,其中username是配置Zookeeper节点之间内部认证的用户名,password是对应的密码。

3、向zookeeper添加Kafka认证插件由于Zookeeper的认证机制是使用插件,这个插件只要支持JAAS即可。Kafka需要链接到Zookeeper,直接使用Kafka的认证插件。这个插件类也包含在kafka-clients中(Maven项目)。将依赖的几个jar加入Zookeeper启动的classpath即可。如下是kafka-clients-0.10.0.1相关jar,可能你的版本和这个不一样,没关系,只要是名字相同就可以,jar在kafka的lib中查找,不需要网上下载。包括其依赖:

kafka-clients-0.10.0.1.jar

lz4-1.3.0.jar

slf4j-api-1.7.21.jar

slf4j-log4j12-1.7.21.jar

snappy-java-1.1.2.6.jar

我的做法比较直接,在Zookeeper部署根目录下创建一个路径for_sasl,将上述所有jar文件复制到这个路径下,再修改bin/zkEnv.sh配置文件,这个文件主要负责加载一些启动Zookeeper有关的环境变量,输入参数。

for i in "$ZOOBINDIR"/../for_sasl/*.jar; 

do CLASSPATH="$i:$CLASSPATH"

done

SERVER_JVMFLAGS=" -Djava.security.auth.login.config=$ZOOCFGDIR/zk_server_jaas.conf "

逻辑比较简单,先将for_sasl目录下的所有jar文件追加到CLASSPATH变量,再设置一个JVM参数给SERVER_JVMFLAGS变量,这两个变量都会在Zookeeper启动时传给JVM。具体可以查看脚本源码。

4、配置其他节点照1到3步骤配置剩余的zookeeper节点。

5、启动所有节点将所有zookeeper节点的Quorum进程开启:bin/zkServer.sh start,查看zookeeper日志,看看之后所有节点是否都能稳定运行,再试试bin/zkCli.sh链接所有节点。是否都能通。

三、 Kafka集群配置SASL确保以上zookeeper配置成功后,开始配置Kafka。Kafka所有节点也是对等的,所以下面步骤的配置在所有节点上都相同。

1、创建JAAS配置文件定义链接Kafka Broker时所需要的用户名密码及broker各个节点之间相互通信的用户名密码,这部分配置定义在KafkaServer节,文件如下:

KafkaServer { 

org.apache.kafka.common.security.plain.PlainLoginModule required 

username="admin" 

password="admin-sec" 

user_admin="admin-sec"

 user_producer="prod-sec" 

user_consumer="cons-sec";

};

Client {

 org.apache.kafka.common.security.plain.PlainLoginModule required 

username="kafka" 

password="kafka-sec";

};

配置文件命名为:kafka_server_jaas.conf,放置在/usr/kafka/kafka_2.11-0.11.0.0/config。下另外Client配置节主要配置了broker到Zookeeper的链接用户名密码。先解释KafkaServer,使用user_来定义多个用户,供客户端程序(生产者、消费者程序)认证使用,可以定义多个,后续配置可能还可以根据不同的用户定义ACL,这部分内容超出本文范围。这是目前我对配置的理解。上例我定义了三个用户,一个是admin,一个是producer,一个是consumer,等号后面是对应用户的密码(如user_producer定义了用户名为producer,密码为prod-sec的用户)。再选择一个用户,用于Kafka内部的各个broker之间通信,这里我选择admin用户,对应的密码是admin-sec。Client配置节则容易理解得多,主要是broker链接到zookeeper,从上文的Zookeeper JAAS文件中选择一个用户,填写用户名和密码即可。

2、配置server.properties

listeners=SASL_PLAINTEXT://vubuntuez1:9092

security.inter.broker.protocol=SASL_PLAINTEXT 

sasl.enabled.mechanisms=PLAIN 

sasl.mechanism.inter.broker.protocol=PLAIN 

authorizer.class.name=kafka.security.auth.SimpleAclAuthorizer

allow.everyone.if.no.acl.found=true

这里注意listeners配置项,将主机名部分(本例主机名是vubuntuez1)替换成当前节点的主机名。其他在各个节点的配置一致。注意,allow.everyone.if.no.acl.found这个配置项默认是false,若不配置成true,后续生产者、消费者无法正常使用Kafka。要么配置成true,这样必须对每个认证用户都配置ACL,比较麻烦,我直接设置true,当没有找到ACL配置时,允许所有的访问操作。

3、配置KAFKA_OPTS环境变量与伪分布式节点配置KAFKA_OPTS变量相同,主要是为了传递JVM变量java.security.auth.login.config,指定JAAS配置文件。然后kafka-run-class.sh会负责将这个KAFKA_OPTS变量传递给JVM。所以启动kafka broker的命令可以与这个设置变量操作写在同一个脚本下:

#!/bin/bashROOT=`dirname $0`

export KAFKA_OPTS=" -Djava.security.auth.login.config=$ROOT/config/kafka_server_jaas.conf "

$ROOT/bin/kafka-server-start.sh -daemon $ROOT/config/server.properties

4、配置其他节点配置剩余的kafka broker节点,注意server.properties的listeners配置项,上文有提到。

5、启动所有的kafka节点启动完成后查看日志,看看是否能稳定运行,不怕抛出异常。运行正常后继续下面的操作。注意,一旦配置Kafka认证后,kafka自带的console-producer和console-consumer都无法使用了。

四、 简单的Producer编写以下所有内容除一部分参数值(比如密码)不同外,其他与伪分布式节点配置SASL的生产者、消费者代码修改流程一致。0.9以后的kafka版本生产者API没有问题,可以直接使用,0.9前的生产者API貌似不支持安全,这个问题具体查看官方文档,更具体的我不了解。0.10后的kafka,生产者代码我不写了,关键说说需要增加的配置操作。

1、添加配置JAVA程序的KafkaProducer初始化需要传入Properties,向Properties实例(假设是props)中加入如下配置项:

props.setProperty ("security.protocol", "SASL_PLAINTEXT");

props.setProperty ("sasl.mechanism", "PLAIN");

2、编写JAAS配置文件这里我们用kafka_client_jaas.conf,此文件为配置客户端的用户名密码文件,配置到java中即可。如/conf/kafka_client_jaas.conf。启动生产者或消费者添加相应的配置文件。

KafkaClient { org.apache.kafka.common.security.plain.PlainLoginModule required 

username="producer" 

password="prod-sec";

};

配置节KafkaClient,默认的是这个,这个名称也可以修改,自行查官方文档。我们使用alice用户。高版本的kafka,其生产者消费者只需要直接链接kafka broker即可,所以不用配置zookeeper。

3、指定JAAS配置文件同理,通过变量java.security.auth.login.config传递给JVM。Kafka的client组件会调用 System.getProperty()这个JDK函数获取到JAAS配置文件路径,所以我们直接使用System.setProperty()设置这个变量为上面创建的kafka_client_jaas.conf文件位置即可。

例如:System.setProperty("java.security.auth.login.config", ""+fsPath+"\\conf\\kafka_client_jaas.conf"); // 环境变量添加,需要输入配置文件的路径 

4、启动生产者提议最好设置一个log4j配置文件,并且设置日志级别为DEBUG,这样就能看见是否正常写入数据。

5、如:本例中生产者 本例中消费者 消费者配置文件 Producer示例代码:

package com.howtoprogram.kafka;

import java.util.Properties;

import org.apache.kafka.clients.producer.KafkaProducer;

import org.apache.kafka.clients.producer.Producer;

import org.apache.kafka.clients.producer.ProducerRecord;

public class ProducerTest {

 public static void main(String[] args) { 

String fsPath=System.getProperty("user.dir"); 

System.setProperty("java.security.auth.login.config", ""+fsPath+"\\conf\\prod_client_jaas.conf"); // 环境变量添加,需要输入配置文件的路径 System.out.println("===================配置文件地址"+fsPath+"\\conf\\prod_client_jaas.conf"); 

Properties props = new Properties(); 

props.put("bootstrap.servers", "192.168.1.203:9092"); 

props.put("acks", "1"); 

props.put("retries", 0); 

props.put("batch.size", 16384); 

props.put("linger.ms", 1); 

props.put("buffer.memory", 33554432); 

props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); 

props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); 

props.setProperty ("security.protocol", "SASL_PLAINTEXT"); 

props.setProperty ("sasl.mechanism", "PLAIN"); 

Producer producer = null; 

try { 

producer = new KafkaProducer<>(props);

 for (int i = 0; i < 100; i++) { 

String msg = "Message " + i; producer.send(new ProducerRecord("HelloKafkaTopic", msg)); 

System.out.println("Sent:" + msg); 

}

 } catch (Exception e) { 

e.printStackTrace();

 } finally { 

producer.close();

 }

 }}


Consumer示例代码:

package com.howtoprogram.kafka;

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 ConsumerTest { public static void main(String[] args) {

String fsPath=System.getProperty("user.dir");

System.setProperty("java.security.auth.login.config", ""+fsPath+"\\conf\\cons_client_jaas.conf"); // 环境变量添加,需要输入配置文件的路径System.out.println("===================配置文件地址"+fsPath+"\\conf\\cons_client_jaas.conf"); 

Properties props = new Properties(); 

props.put("bootstrap.servers", "192.168.1.203:9092"); 

props.put("group.id", "group-1"); 

props.put("enable.auto.commit", "true"); 

props.put("auto.commit.interval.ms", "1000"); 

props.put("auto.offset.reset", "earliest"); 

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"); 

props.setProperty ("security.protocol", "SASL_PLAINTEXT"); 

props.setProperty ("sasl.mechanism", "PLAIN"); 

KafkaConsumer kafkaConsumer = new KafkaConsumer<>(props); 

kafkaConsumer.subscribe(Arrays.asList("HelloKafkaTopic"));

 while (true) { 

ConsumerRecords records = kafkaConsumer.poll(100); 

for (ConsumerRecord record : records) { 

System.out.println("Partition: " + record.partition() + " Offset: " + record.offset() + " Value: " + record.value() + " ThreadID: " + Thread.currentThread().getId()); 

}

  }

}

五:可能遇到的问题程序启动后控制台没有报错,但是半天没反应,首先查看linux防火墙

执行: service iptables stop ;chkconfig iptables off;检查程序端client文件的用户名密码配置是否正确。

六:Kafka安全配置的必要性:Kafka是由LinkedIn设计的一个高吞吐量、分布式、基于发布订阅模式的消息系统,使用Scala编写,它以可水平扩展、可靠性、异步通信和高吞吐率等特性而被广泛使用。目前越来越多的开源分布式处理系统都支持与Kafka集成,其中Spark Streaming作为后端流引擎配合Kafka作为前端消息系统正成为当前流处理系统的主流架构之一。然而,当下越来越多的安全漏洞、数据泄露等问题的爆发,安全正成为系统选型不得不考虑的问题,Kafka由于其安全机制的匮乏,也导致其在数据敏感行业的部署存在严重的安全隐患。本文将围绕Kafka,先介绍其整体架构和关键概念,再深入分析其架构之中存在的安全问题,最后分享下Transwarp在Kafka安全性上所做的工作及其使用方法。Kafka架构与安全首先,我们来了解下有关Kafka的几个基本概念:Topic:Kafka把接收的消息按种类划分,每个种类都称之为Topic,由唯一的Topic Name标识。Producer:向Topic发布消息的进程称为Producer。Consumer:从Topic订阅消息的进程称为Consumer。Broker:Kafka集群包含一个或多个服务器,这种服务器被称为Broker。Kafka的整体架构如下图所示,典型的Kafka集群包含一组发布消息的Producer,一组管理Topic的Broker,和一组订阅消息的Consumer。Topic可以有多个分区,每个分区只存储于一个Broker。Producer可以按照一定的策略将消息划分给指定的分区,如简单的轮询各个分区或者按照特定字段的Hash值指定分区。Broker需要通过ZooKeeper记录集群的所有Broker、选举分区的Leader,记录Consumer的消费消息的偏移量,以及在Consumer Group发生变化时进行relalance. Broker接收和发送消息是被动的:由Producer主动发送消息,Consumer主动拉取消息。 然而,分析Kafka框架,我们会发现以下严重的安全问题:1.网络中的任何一台主机,都可以通过启动Broker进程而加入Kafka集群,能够接收Producer的消息,能够篡改消息并发送给Consumer。2.网络中的任何一台主机,都可以启动恶意的Producer/Consumer连接到Broker,发送非法消息或拉取隐私消息数据。3.Broker不支持连接到启用Kerberos认证的ZooKeeper集群,没有对存放在ZooKeeper上的数据设置权限。任意用户都能够直接访问ZooKeeper集群,对这些数据进行修改或删除。4.Kafka中的Topic不支持设置访问控制列表,任意连接到Kafka集群的Consumer(或Producer)都能对任意Topic读取(或发送)消息。随着Kafka应用场景越来越广泛,特别是一些数据隐私程度较高的领域(如道路交通的视频监控),上述安全问题的存在犹如一颗定时炸弹,一旦内网被黑客入侵或者内部出现恶意用户,所有的隐私数据(如车辆出行记录)都能够轻易地被窃取,而无需攻破Broker所在的服务器。Kafka安全设计基于上述分析,Transwarp从以下两个方面增强Kafka的安全性:身份认证(Authentication):设计并实现了基于Kerberos和基于IP的两种身份认证机制。前者为强身份认证,相比于后者具有更好的安全性,后者适用于IP地址可信的网络环境,相比于前者部署更为简便。权限控制(Authorization):设计并实现了Topic级别的权限模型。Topic的权限分为READ(从Topic拉取数据)、WRITE(向Topic中生产数据)、CREATE(创建Topic)和DELETE(删除Topic)。基于Kerberos的身份机制如下图所示: Broker启动时,需要使用配置文件中的身份和密钥文件向KDC(Kerberos服务器)认证,认证通过则加入Kafka集群,否则报错退出。Producer(或Consumer)启动后需要经过如下步骤与Broker建立安全的Socket连接:1.Producer向KDC认证身份,通过则得到TGT(票证请求票证),否则报错退出2.Producer使用TGT向KDC请求Kafka服务,KDC验证TGT并向Producer返回SessionKey(会话密钥)和ServiceTicket(服务票证)3.Producer使用SessionKey和ServiceTicket与Broker建立连接,Broker使用自身的密钥解密ServiceTicket,获得与Producer通信的SessionKey,然后使用SessionKey验证Producer的身份,通过则建立连接,否则拒绝连接。ZooKeeper需要启用Kerberos认证模式,保证Broker或Consumer与其的连接是安全的。Topic的访问控制列表(ACL)存储于ZooKeeper中,存储节点的路径为/acl//,节点数据为R(ead)、W(rite)、C(reate)、D(elete)权限的集合,如/acl/transaction/jack节点的数据为RW,则表示用户jack能够对transaction这个topic进行读和写。另外,kafka为特权用户,只有kafka用户能够赋予/取消权限。因此,ACL相关的ZooKeeper节点权限为kafka具有所有权限,其他用户不具有任何权限。


第一次发帖。同时感谢http://blog.csdn.net/u012842205/article/details/73188684文章的作者,给了我很大帮助!

阅读全文
1 0