一、使用SSL加密和认证
为每个Kafka broker生成SSL密钥和证书。
部署HTTPS,第一步是为集群的每台机器生成密钥和证书,可以使用java的keytool来生成密钥到一个临时的密钥库,之后可以导出并用CA签名它。keytool -keystore server.keystore.jks -alias localhost -validity {validity} -genkey
keystore: 密钥仓库存储证书文件。密钥仓库文件包含证书的私钥(保证私钥的安全)。
validity: 证书的有效时间,天
注意:默认情况下,不会定义ssl.endpoint.identification.algorithm,所以不会执行主机名验证。 要启用主机名验证,请设置以下属性:ssl.endpoint.identification.algorithm=HTTPS
一旦启用,客户端将根据以下两个字段之一验证服务器的完全限定域名(FQDN):
Common Name (CN)
Subject Alternative Name (SAN)
两个字段都有效,但RFC-2818建议使用SAN。 SAN更灵活,允许声明多个DNS条目。 另一个优点是,CN可以设置为更有意义的值用于授权。 要添加SAN字段,可用以下参数-ext SAN = DNS:{FQDN}: keytool -keystore server.keystore.jks -alias localhost -validity {validity} -genkey -ext SAN=DNS:{FQDN}
之后可以运行以下命令来验证生成的证书的内容:
keytool -list -v -keystore server.keystore.jks
创建自己的CA
通过第一步,集群中的每台机器都生成了一对公私钥,和一个证书来识别机器。但是,证书是未签名的,这意味着攻击者可以创建一个这样的证书来假装成任何机器。
因此,通过对集群中的每台机器进行签名来防止伪造的证书。证书颁发机构(CA)负责签名证书。CA的工作机制像一个颁发护照的政府。政府印章(标志)每本护照,这样护照很难伪造。其他政府核实护照的印章,以确保护照是真实的。同样,CA签名的证书和加密保证签名证书很难伪造。因此,只要CA是一个真正和值得信赖的权威,client就能有较高的保障连接的是真正的机器。openssl req -new -x509 -keyout ca-key -out ca-cert -days 365
生成的CA是一个简单的公私钥对和证书,用于签名其他的证书。
下一步是将生成的CA添加到clients’ truststore(客户的信任库),以便client可以信任这个CA:keytool -keystore client.truststore.jks -alias CARoot -import -file ca-cert
注意,还需设置ssl.client.auth(”requested” 或 “required”),来要求broker对客户端连接进行验证,当然,你必须为broker提供信任库以及所有客户端签名了密钥的CA证书,通过下面的命令:
keytool -keystore server.truststore.jks -alias CARoot -import -file ca-cert
相反,在步骤1中,密钥库存储了每个机器自己的身份。客户端的信任库存储所有客户端信任的证书,将证书导入到一个信任仓库也意味着信任由该证书签名的所有证书,正如上面的比喻,信任政府(CA)也意味着信任它颁发的所有护照(证书),此特性称为信任链,在大型的kafka集群上部署SSL时特别有用的。可以用单个CA签名集群中的所有证书,并且所有的机器共享相同的信任仓库,这样所有的机器也可以验证其他的机器了。
签名证书
用步骤2生成的CA来签名所有步骤1生成的证书,首先,你需要从密钥仓库导出证书:
keytool -keystore server.keystore.jks -alias localhost -certreq -file cert-file
然后用CA签名:
openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days {validity} -CAcreateserial -passin pass:{ca-password}
最后,你需要导入CA的证书和已签名的证书到密钥仓库:
keytool -keystore server.keystore.jks -alias CARoot -import -file ca-cert keytool -keystore server.keystore.jks -alias localhost -import -file cert-signed
keystore: 密钥仓库的位置
ca-cert: CA的证书
ca-key: CA的私钥
ca-password: CA的密码
cert-file: 出口,服务器的未签名证书
cert-signed: 已签名的服务器证书
以下是上面所有步骤的一个bash脚本例子。注意,这里假设密码“test1234”:#!/bin/bash #Step 1 keytool -keystore server.keystore.jks -alias localhost -validity 365 -genkey #Step 2 openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 keytool -keystore server.truststore.jks -alias CARoot -import -file ca-cert keytool -keystore client.truststore.jks -alias CARoot -import -file ca-cert #Step 3 keytool -keystore server.keystore.jks -alias localhost -certreq -file cert-file openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days 365 -CAcreateserial -passin pass:test1234 keytool -keystore server.keystore.jks -alias CARoot -import -file ca-cert keytool -keystore server.keystore.jks -alias localhost -import -file cert-signed
配置Kafka broker
Kafka Broker支持监听多个端口上的连接,通过server.properteis 配置,最少监听1个端口,用逗号分隔。
如果broker之间通讯未启用SSL(参照下面,启动它),PLAINTEXT和SSL端口是必须要配置。listeners=PLAINTEXT://host.name:port,SSL://host.name:port
下面是broker端需要的SSL配置:
ssl.keystore.location=/var/private/ssl/kafka.server.keystore.jks ssl.keystore.password=test1234 ssl.key.password=test1234 ssl.truststore.location=/var/private/ssl/kafka.server.truststore.jks ssl.truststore.password=test1234
下面是可选的配置:
①.ssl.client.auth = none (“required”=>客户端身份验证是必需的,“requested”=>客户端身份验证请求,客户端没有证书仍然可以连接。使用“requested”是纸老虎,因为它提供了一种虚假的安全感,错误的配置客户端仍将连接成功。)
②.ssl.cipher.suites(可选)。密码套件是利用TLS或SSL网络协议的网络连接的安全设置。是认证,加密,MAC和密钥交换算法的组合。 (默认值是一个空表)
③.ssl.enabled.protocols = TLSv1.2 TLSv1.1 TLSv1 (接收来自客户端列出的SSL协议,注意,不推荐在生产中使用SSL,推荐使用TLS)。
④.ssl.keystore.type=JKS
⑤.ssl.truststore.type=JKS
如果你想启用SSL用于broker内部通讯,将以下内容添加到broker配置文件(默认是PLAINTEXT)security.inter.broker.protocol=SSL
用以下命令,验证服务器的keystore和truststore设置是否正确:
openssl s_client -debug -connect localhost:9093 -tls1
配置Kafka客户端
SSL仅支持新的Producer和Consumer,不支持老的API,Producer和Consumer的SSL的配置是相同的。
如果broker中不需要client(客户端)验证,那么下面是最小的配置示例:security.protocol=SSL ssl.truststore.location=/var/private/ssl/kafka.client.truststore.jks ssl.truststore.password=test1234
注意:ssl.truststore.password在技术上是可选的,但强烈推荐。 如果未设置密码,对信任库的访问仍然可用,就不属于完整性检查。 如果需要客户端认证,则必须像步骤1一样创建密钥库,并且还必须配置以下内容:
ssl.keystore.location=/var/private/ssl/kafka.client.keystore.jks ssl.keystore.password=test1234 ssl.key.password=test1234
举个例子,使用 console-producer 和 console-consumer :
kafka-console-producer.sh --broker-list localhost:9093 --topic test --producer.config client-ssl.properties kafka-console-consumer.sh --bootstrap-server localhost:9093 --topic test --consumer.config client-ssl.properties
二、SASL认证
JAAS配置
Kafka使用Java认证和授权服务(JAAS)进行SASL配置。
为broker配置JAAS
KafkaServer是每个KafkaServer/Broker使用JAAS文件中的部分名称。本节为broker提供了SASL配置选项,包括进行broker之间通信所需的任何SASL客户端连接。
客户端部分用于验证与zookeeper的SASL连接。它还允许broker在zookeeper节点上设置SASL ACL。并锁定这些节点,以便只有broker可以修改它。所有的broker必须有相同的principal名称。如果要使用客户端以外的名称,设置zookeeper.sasl.client(例如,-Dzookeeper.sasl.client = ZkClient)。
默认情况下,Zookeeper使用“zookeeper”作为服务名称。如果你需要修改,设置zookeeper.sasl.client.user(例如,-Dzookeeper.sasl.client.username=zk)
Kafka客户端的JAAS配置
客户端可以使用客户端配置属性sasl.jaas.config或使用broker类似的静态JAAS配置文件配置JAAS。
JAAS配置使用客户端配置属性
客户端可以将JAAS配置指定为生产者或消费者属性,而不创建物理配置文件。 此模式还使同一个JVM中的不同生产者和消费者通过为每个客户端指定不同的属性来使用不同的凭据。 如果指定了静态JAAS配置系统属性java.security.auth.login.config和客户端属性sasl.jaas.config,将使用客户端属性。
使用静态配置文件的JAAS配置
使用静态JAAS配置文件来配置客户端上的SASL认证。
添加一个名为KafkaClient的客户端登录部分的JAAS配置文件。 在KafkaClient中为所选机制配置登录模块,如设置GSSAPI(Kerberos),PLAIN或SCRAM的示例中所述。 例如,GSSAPI凭据可以配置为:KafkaClient { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab="/etc/security/keytabs/kafka_client.keytab" principal="kafka-client-1@EXAMPLE.COM"; };
将JAAS配置文件位置作为JVM参数传递给每个客户端JVM。 例如:
-Djava.security.auth.login.config=/etc/kafka/kafka_client_jaas.conf
SASL配置
SASL可以使用PLAINTEXT或SSL作为传输层,分别使用安全协议SASL_PLAINTEXT或SASL_SSL。 如果使用SASL_SSL,则还必须配置SSL。
SASL机制
Kafka支持以下的SASL机制:
GSSAPI (Kerberos)
PLAIN
SCRAM-SHA-256
SCRAM-SHA-512
为Kafka broker配置SASL
在server.properteis配置一个SASL端口,SASL_PLAINTEXT或SASL_SSL至少增加一个到listeners,用逗号分隔: listeners=SASL_PLAINTEXT://host.name:port
如果你只配置一个SASL端口(如果你需要broker使用SASL互相验证),那么需要确保broker之间设置相同的SASL协议:security.inter.broker.protocol=SASL_PLAINTEXT (or SASL_SSL)
选择一个或多个支持的机制,并通过以下的步骤为机器配置SASL。在broker之间启用多个机制:
为Kafka客户端配置SASL
SASL仅支持新的java生产者和消费者,不支持老的API。
要在客户端上配置SASL验证,选择在broker中启用的客户端身份验证的SASL机制,并按照以下步骤配置所选机制的SASL。使用SASL/Kerberos认证
预备知识
Kerberos
如果你已在使用Kerberos(如,使用Active Directory),则无需安装重新安装。否则,你将需要安装一个,Linux供应商有Kerberos安装和配置的简短说明(Ubuntu,Radhat)。请注意,如果你使用的是Oracle Java,你需要下载java版本的JCE策略文件,将它们复制到 $JAVA_HOME/jre/lib/security中(注意:必须替换!!).
创建Kerberos Principals
通过以下命令创建你自己的principal。sudo /usr/sbin/kadmin.local -q 'addprinc -randkey kafka/{hostname}@{REALM}' sudo /usr/sbin/kadmin.local -q "ktadd -k /etc/security/keytabs/{keytabname}.keytab kafka/{hostname}@{REALM}"
确保使用主机名可以访问所有主机 - Kerberos要求所有的host都可以用其FQDN解析所有主机。
配置Broker
添加一个JAAS文件,类似下面的每个kafka broker的配置目录。这个例子我们姑且命名为kafka_server_jaas.conf(注意,每个broker都应该有自己的密钥表) KafkaServer { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab="/etc/security/keytabs/kafka_server.keytab" principal="kafka/kafka1.hostname.com@EXAMPLE.COM"; }; // Zookeeper client authentication Client { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab="/etc/security/keytabs/kafka_server.keytab" principal="kafka/kafka1.hostname.com@EXAMPLE.COM"; };
JAAS文件中的KafkaServer部分告诉broker哪个principal要使用,以及存储该principal的keytab的位置。它允许broker使用本节中指定的keytab进行登录。更多细节参见zookeeper的SASL配置。
通过JAAS和krb5文件位置(可选的)作为JVM参数传递到每个broker。(更多细节):-Djava.security.krb5.conf=/etc/kafka/krb5.conf -Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf
确保在JAAS文件的keytabs配置文件可被启动的Broker的操作系统员读取。
在server.properties中配置SASL端口和SASL机制,例如:listeners=SASL_PLAINTEXT://host.name:port security.inter.broker.protocol=SASL_PLAINTEXT sasl.mechanism.inter.broker.protocol=GSSAPI sasl.enabled.mechanisms=GSSAPI
我们还必须在server.properties配置服务器名称,应与broker的principal名匹配,在上面的例子中,principal是”kafka/kafka1.hostname.com@EXAMPLE.com”, 所以:
sasl.kerberos.service.name=kafka
配置Kafka客户端
在客户端上配置SASL认证
客户端(生产者,消费者,connect,等等)用自己的principal进行集群认证(通常用相同名称作为运行客户端的用户)。因此,获取或根据需要创建这些principal。然后为每个客户端配置JAAS配置属性。JVM中的不同客户端通过指定不同的principal可以作为不同的用户运行。producer.properties或consumer.properties中的属性sasl.jaas.config描述了像生产者和消费者之类的客户端如何连接到Kafka Broker的。 以下是使用keytab的客户端的示例配置(推荐用于长时间运行的进程):sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required \ useKeyTab=true \ storeKey=true \ keyTab="/etc/security/keytabs/kafka_client.keytab" \ principal="kafka-client-1@EXAMPLE.COM";
对于像kafka-console-consumer或kafka-console-producer这样的命令行工具,kinit可以与“useTicketCache=true”一起使用,如:
sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
客户端的JAAS配置可以作为JVM参数,类似于broker。 客户端使用名为KafkaClient的login部分。 此选项仅允许JVM中所有客户端连接的一个用户。
确保JAAS配置中的keytabls配置文件能被启动kafka客户端的操作系统用户读取。
可以将krb5文件位置作为JVM参数传递给每个客户端JVM(有关详细信息,请参阅此处):-Djava.security.krb5.conf=/etc/kafka/krb5.conf 在 producer.properties 或 consumer.properties中配置以下属性: security.protocol=SASL_PLAINTEXT (or SASL_SSL) sasl.mechanism=GSSAPI sasl.kerberos.service.name=kafka
使用SASL/PLAIN认证
SASL/PLAIN是一种简单的用户名/密码的认证机制,通常与TLS加密一起使用,以实现安全的认证。Kafka支持SASL/PLAIN的默认实现,可作为生产者的扩展使用。username用作ACL等配置已认证的Principal。
配置Kafka Brokers
在每个Kafka broker的config目录下添加一个类似于下面的修改后的JAAS文件,我们姑且将其称为kafka_server_jaas.conf。 KafkaServer { org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="admin-secret" user_admin="admin-secret" user_alice="alice-secret"; };
此配置定义了2个用户(admin 和 alice)。 在KafkaServer中,username和password是broker用于初始化连接到其他的broker,在这个例子中,admin是broker之间通信的用户。user_userName定义了所有连接到broker和broker验证的所有的客户端连接包括其他broker的用户密码。
将JAAS配置文件位置作为JVM参数传递给每个Kafka broker:-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf
在server.properties中配置SASL端口和SASL机制。 例如:
listeners=SASL_SSL://host.name:port security.inter.broker.protocol=SASL_SSL sasl.mechanism.inter.broker.protocol=PLAIN sasl.enabled.mechanisms=PLAIN
配置kafka客户端
在客户端上配置SASL身份验证:
为producer.properties或consumer.properties中的每个客户端配置JAAS。登录模块展示了客户端如何连接Broker的(和生产者和消费者一样)。 以下是PLAIN机制的客户端的示例配置:sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \ username="alice" \ password="alice-secret";
客户端选择用户名和密码为客户端配置连接的用户。 在此示例中,客户端以用户alice连接到broker。也可以通过在sasl.jaas.config中指定不同的用户名和密码,JVM中的不同客户端可以根据不同的用户来进行连接。
客户端的JAAS配置可以指定为类似于这里描述的broker作为JVM参数。客户端使用的命名为KafkaClient。 此选项仅允许来自JVM的所有客户端连接中的一个用户。
在producer.properties或consumer.properties中配置以下属性:security.protocol=SASL_SSL sasl.mechanism=PLAIN
在生产者中使用SASL/PLAIN
SASL/PLAIN应仅用SSL作为传输层,以确保在没有加密的情况下不会在线上明文传输。
Kafka中SASL/PLAIN的默认实现是在JAAS配置文件中的用户名和密码,如下所示。为了避免在磁盘上存储密码,你可以自己用javax.security.auth.spi.LoginModule实现,从外部源获取用户名和密码。登录模块应该提供Subject的用户名作为公共证书和密码作为私人凭证。 可以使用默认实现org.apache.kafka.common.security.plain.PlainLoginModule作为参考。
在生产者系统中,外部认证服务器可以实现密码验证。Kafka broker可以与这些服务器集成(通过添加自己实现 javax.security.sasl.SaslServer)。在这个包路径org.apache.kafka.common.security.plain中,包括在kafka的默认的实现,可以作为一个参考的实例。
必须在JVM中安装和注册新的Providers(提供者)。可以通过将提供程序类添加到CLASSPATH或打包成jar文件并将其添加到JAVA_HOME/lib/ext来安装提供者。
也可以通过添加Providers到安全属性文件 JAVA_HOME/lib/security/java.security中静态的注册Providers。security.provider.n=providerClassName
其中,providerClassName是新Provider的全名,n是优先排序(较低的数字表明更高的优先权)
此外,你可以在运行时通过在客户端应用程序的开始调用Security.addProvider或登录模块中的静态初始化程序来动态注册provider。 例如:Security.addProvider(new PlainSaslServerProvider());
使用 SASL/SCRAM 认证
SCRAM(Salted Challenge Response Authentication Mechanism)是SASL机制家族的一种,
,通过执行用户名/密码认证(如PLAIN和DIGEST-MD5)的传统机制来解决安全问题。 该机制在RFC 5802中定义。Kafka支持SCRAM-SHA-256和SCRAM-SHA-512,可与TLS一起使用执行安全认证。 用户名用作配置ACL等认证的principal。Kafka中的默认SCRAM实现是在Zookeeper中存储SCRAM的证书,适用于Zookeeper在私有网络上的Kafka安装。 有关详细信息,请参阅安全注意事项
创建 SCRAM 证书
Kafka的SCRAM实现使用Zookeeper作为证书存储。通过使用kafka-configs.sh来创建证书。 对于启用的每个SCRAM机制,必须通过使用机制名称添加配置来创建证书。 必须在kafka broker启动之前创建broker之间通信的证书。 客户端证书可以动态创建和更新,并且将使用更新后的证书来验证新的连接。
为用户alice创建SCRAM凭证(密码为alice-secret):bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[iterations=8192,password=alice-secret],SCRAM-SHA-512=[password=alice-secret]' --entity-type users --entity-name alice
如果未指定迭代数,则使用默认迭代数为4096。 创建一个随机salt,由salt,迭代,StoredKey和ServerKey组成的SCRAM标识,都存储在Zookeeper中。 有关SCRAM身份和各个字段的详细信息,请参阅RFC 5802。
以下示例中,需要用户admin进行broker间通信,通过以下命令创建:bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=admin-secret],SCRAM-SHA-512=[password=admin-secret]' --entity-type users --entity-name admin
可以使用–describe列出现有的证书:
bin/kafka-configs.sh --zookeeper localhost:2181 --describe --entity-type users --entity-name alice
可以使用–delete为一个或多个SCRAM机制删除证书:
bin/kafka-configs.sh --zookeeper localhost:2181 --alter --delete-config 'SCRAM-SHA-512' --entity-type users --entity-name alice
配置Kafka Broker
在每个Kafka broker的config目录下添加一个类似于下面的JAAS文件,我们姑且将其称为kafka_server_jaas.conf: KafkaServer { org.apache.kafka.common.security.scram.ScramLoginModule required username="admin" password="admin-secret" };
其中,broker使用KafkaServer中的用户名和密码来和其他broker进行连接。 在这个例子中,admin是broker之间通信的用户。
JAAS配置文件的位置作为JVM参数传递给每个Kafka broker:-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf
在server.properties中配置SASL端口和SASL机制。 例如:
listeners=SASL_SSL://host.name:port security.inter.broker.protocol=SASL_SSL sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256 (or SCRAM-SHA-512) sasl.enabled.mechanisms=SCRAM-SHA-256 (or SCRAM-SHA-512)
配置kafka客户端
在客户端上配置SASL认证
为每个客户端配置JAAS配置(在producer.properteis或consumer.properteis)。登录模块展示了客户端(如生产者和消费者)如何连接到broker的。下面是配置了SCRAM机制的客户端的例子。sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="alice" password="alice-secret";
客户端使用username和password来配置客户端连接的用户。在这个例子中,客户端使用用户alice连接broker。在JVM中不同的客户端连接不同的用户(通过在sasl.jaas.config中指定不同的用户名和密码)。
客户端的JAAS配置通过指定作为JVM的参数。使用名为KafkaCLient的客户端登录。此选择仅允许来自JVM的所有客户端连接中的一个用户。
在producer.properties或consumer.properties中配置以下参数:security.protocol=SASL_SSL sasl.mechanism=SCRAM-SHA-256 (or SCRAM-SHA-512)
SASL/SCRAM安全注意事项
在kafka中SASL/SCRAM的默认实现SCRAM证书存储在Zookeeper中,这适用于Zookeeper安全和私有网络生产部署。
Kafka仅支持强散列函数SHA-256和SHA-512,最小迭代次数为4096.强散列函数结合强密码和高迭代数可以防止强制攻击(如果Zookeeper安全性受到威胁)。
SCRAM只能使用TLS加密,以防止拦截SCRAM交换。如果Zookeeper受到威胁,则可以防止字典或暴力攻击,和防止伪装模仿。
可以使用Zookeeper(不安全)安装自定义登录模块来覆盖默认的SASL/SCRAM实现。
在broker中启用多个SASL机制
在JAAS文件中的KafkaServer中启用所有机制的登录模块配置。例如:KafkaServer { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab="/etc/security/keytabs/kafka_server.keytab" principal="kafka/kafka1.hostname.com@EXAMPLE.COM"; org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="admin-secret" user_admin="admin-secret" user_alice="alice-secret"; };
在server.properties中启用SASL机制sasl.enabled.mechanisms=GSSAPI,PLAIN,SCRAM-SHA-256,SCRAM-SHA-512
如果需要broker之间通讯,则在server.properteis中指定SASL安全协议和机制。security.inter.broker.protocol=SASL_PLAINTEXT (or SASL_SSL) sasl.mechanism.inter.broker.protocol=GSSAPI (or one of the other enabled mechanisms)
按照机制 - GSSAPI(Kerberos),PLAIN和SCRAM中的具体步骤来配置启用的SASL机制。
在运行的集群中修改SASL机制
可以按照以下顺序在正在运行的群集中修改SASL机制:
将新SASL机制添加到每个broker上的server.properteis中的sasl.enabled.mechanisms上。更新JAAS配置文件以包括这两个机制,如这里所述。 逐步重启群集节点。
使用新机制重新启动集群。
要改变broker之间的通讯(如果需要),则设置在server.properteis中的sasl.mechanism.inter.broker.protocol为新的机制并逐个重启。
要移除老的机制(如果需要),从server.properties的sasl.enabled.mechanisms和JAAS配置文件中移除旧机制。然后依次重启。