Kafka 支持 SSL(Secure Sockets Layer,现为 TLS),用于 加密传输 和 身份认证,可以防止数据被窃听或篡改,适用于生产环境。
Kafka SSL(TLS)的作用是确保数据在传输过程中的安全性、身份验证、数据完整性以及防止中间人攻击等。通过以下几个核心功能,SSL/TLS 协议可以有效保护 Kafka 集群免受各种网络安全威胁。以下是详细的作用介绍,并结合具体事例进行解释。
作用:
Kafka 使用 SSL/TLS 来加密客户端与 Kafka Broker 之间的数据传输。这确保了数据在传输过程中不会被第三方窃取,即使数据包被截获,也无法读取其中的内容。
举例说明:
有一个电商平台的 Kafka 集群,消费者和生产者交换订单信息,订单内容包括客户的个人信息、支付卡信息等。如果没有 SSL 加密,这些敏感信息在传输过程中可能会被中间人(比如攻击者)监听和窃取。
加密后的情况:
作用:
SSL/TLS 协议可以实现双方的身份验证,确保通信的双方都是可信的。Kafka 使用双向认证,既验证 Kafka Broker 的身份,也验证客户端(生产者或消费者)的身份。
举例说明:
假设在公司内部署 Kafka 集群,并且需要确保只有合法的客户端才能访问 Kafka 服务。你配置了双向 SSL 认证,以确保客户端和服务器的身份都被验证。
身份认证后的情况:
作用:
SSL/TLS 协议可以通过消息认证码(MAC)来验证数据是否在传输过程中被篡改。它确保数据传输的完整性,防止消息被第三方修改。
举例说明:
假设在一个 Kafka 集群,生产者将订单信息发送到 Kafka。为了确保数据传输过程中不被篡改,Kafka 启用了 SSL/TLS 的完整性校验。
数据完整性后的情况:
作用:
中间人攻击(MITM)是指攻击者伪装成通信双方之一,窃取或篡改数据。SSL/TLS 可以有效防止这种攻击,通过加密通信和身份验证,确保只有合法的客户端和服务器能建立通信。
举例说明:
假设你有一个 Kafka 集群部署在公共云中,且客户端(生产者和消费者)与 Kafka Broker 之间的网络是不安全的。在没有 SSL/TLS 加密的情况下,攻击者可以伪装成 Kafka Broker,拦截客户端的数据流,并获取敏感信息。
防止中间人攻击后的情况:
作用:
Kafka 是一个分布式系统,集群中的各个 Broker 需要进行内部通信,SSL 可以确保 Broker 之间的通信安全,防止敏感配置或数据泄露。
举例说明:
假设你有一个跨多个数据中心的 Kafka 集群,Kafka Broker 在不同数据中心之间进行通信。没有 SSL 加密,Broker 之间的敏感信息(如集群状态、配置等)可能会被窃取。
安全的分布式环境后的情况:
作用:
SSL 还可以用于拒绝非法连接。通过验证客户端的身份,Kafka 可以防止非法客户端或恶意攻击者通过伪造连接耗尽 Kafka 集群的资源,从而防止拒绝服务(DoS)攻击。
举例说明:
假设你运行的是一个互联网服务平台,Kafka 集群需要保证只有经过验证的客户端(例如合法的生产者或消费者)才能连接。
防止 DoS 攻击后的情况:
通过这些安全功能,Kafka 能够在开放的网络环境中提供更高的安全性,确保数据的安全传输和系统的可靠性。
Kafka 需要 密钥对(Keystore)和受信任证书(Truststore),我们可以使用 keytool
生成:
# 生成 Kafka Broker 证书
keytool -genkey -keystore kafka.server.keystore.jks -validity 365 -storepass kafka123 -keypass kafka123 -dname "CN=KafkaBroker, OU=MyOrg, O=MyCompany, L=MyCity, ST=MyState, C=MyCountry"
# 生成 CA 证书(自签名)
openssl req -new -x509 -keyout ca-key -out ca-cert -days 365 -nodes
# 将 CA 证书导入 Kafka Truststore
keytool -keystore kafka.server.truststore.jks -alias CARoot -import -file ca-cert -storepass kafka123
# 签署 Kafka 证书
keytool -keystore kafka.server.keystore.jks -alias kafka-broker -certreq -file kafka-cert-request -storepass kafka123
openssl x509 -req -CA ca-cert -CAkey ca-key -in kafka-cert-request -out kafka-signed-cert -days 365 -CAcreateserial
# 导入 CA 和 Kafka 签名证书
keytool -keystore kafka.server.keystore.jks -alias CARoot -import -file ca-cert -storepass kafka123
keytool -keystore kafka.server.keystore.jks -alias kafka-broker -import -file kafka-signed-cert -storepass kafka123
修改 Kafka server.properties
以启用 SSL:
listeners=SSL://0.0.0.0:9093
advertised.listeners=SSL://your.kafka.server:9093
ssl.keystore.location=/etc/kafka/kafka.server.keystore.jks
ssl.keystore.password=kafka123
ssl.key.password=kafka123
ssl.truststore.location=/etc/kafka/kafka.server.truststore.jks
ssl.truststore.password=kafka123
ssl.client.auth=required # 启用双向认证(如果仅 Broker 认证,改为 "none")
然后 重启 Kafka:
bin/kafka-server-stop.sh
bin/kafka-server-start.sh -daemon config/server.properties
创建 producer.properties
:
security.protocol=SSL
ssl.truststore.location=/etc/kafka/kafka.client.truststore.jks
ssl.truststore.password=kafka123
ssl.keystore.location=/etc/kafka/kafka.client.keystore.jks
ssl.keystore.password=kafka123
ssl.key.password=kafka123
测试发送消息:
kafka-console-producer.sh --broker-list your.kafka.server:9093 --topic test-topic --producer.config producer.properties
创建 consumer.properties
:
security.protocol=SSL
ssl.truststore.location=/etc/kafka/kafka.client.truststore.jks
ssl.truststore.password=kafka123
ssl.keystore.location=/etc/kafka/kafka.client.keystore.jks
ssl.keystore.password=kafka123
ssl.key.password=kafka123
测试消费消息:
kafka-console-consumer.sh --bootstrap-server your.kafka.server:9093 --topic test-topic --from-beginning --consumer.config consumer.properties
Kafka 和 ZooKeeper 的通信默认是 PLAINTEXT,可以使用 SSL:
zookeeper.connect=localhost:2182
zookeeper.ssl.client.enable=true
zookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty
zookeeper.ssl.keystore.location=/etc/kafka/zookeeper.keystore.jks
zookeeper.ssl.keystore.password=zookeeper123
zookeeper.ssl.truststore.location=/etc/kafka/zookeeper.truststore.jks
zookeeper.ssl.truststore.password=zookeeper123
netstat -tulnp | grep 9093
如果 Kafka 正常监听:
tcp6 0 0 :::9093 :::* LISTEN 1234/java
openssl s_client -connect your.kafka.server:9093
如果连接正常,会显示:
SSL handshake has read 2000 bytes
---
Certificate chain
0 s:/CN=KafkaBroker
Kafka 支持多种安全配置模式,其中包括 PLAINTEXT、SSL(单向认证) 和 SSL(双向认证)。这些配置方式有不同的安全性和性能考虑。
定义:
PLAINTEXT 是 Kafka 的默认配置,它意味着所有的通信数据都是以明文方式进行传输,没有加密或身份验证。这是 Kafka 最简单的配置方式,适用于不涉及敏感数据的环境。
作用:
配置:
listeners=PLAINTEXT://0.0.0.0:9092
advertised.listeners=PLAINTEXT://your-broker-hostname:9092
具体事例:
假设你在一个内部开发环境中使用 Kafka,数据安全性不是重点需求,且集群的所有节点都位于可信的网络中。在这种情况下,使用 PLAINTEXT 配置是最简单和性能最好的选择。然而,这种配置方式不能在生产环境中使用,特别是当处理敏感数据时。
定义:
SSL 单向认证配置使用 SSL/TLS 加密来保护客户端和 Kafka Broker 之间的通信,但只验证 Broker 的身份。客户端不需要提供证书,只需验证 Broker 的证书是否合法。
作用:
配置:
Kafka Broker 配置:
listeners=SSL://0.0.0.0:9093
advertised.listeners=SSL://your-broker-hostname:9093
# 配置 SSL 密钥库和信任库
ssl.keystore.location=/path/to/kafka.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/path/to/kafka.truststore.jks
ssl.truststore.password=changeit
# 配置客户端认证方式为 "none",表示客户端不需要证书
ssl.client.auth=none
security.inter.broker.protocol=SSL
生产者/消费者配置:
security.protocol=SSL
ssl.truststore.location=/path/to/kafka.truststore.jks
ssl.truststore.password=changeit
具体事例:
假设你在一个企业环境中,Kafka 集群主要用于内部系统的数据传输,客户端(如生产者)并不需要进行身份验证。此时,你可以通过启用 SSL 单向认证 来保护数据的加密传输,并确保客户端连接的 Kafka Broker 是合法的。
定义:
SSL 双向认证配置不仅使用 SSL/TLS 加密保护数据传输,而且 客户端和服务器(Broker)之间都进行身份验证。客户端和 Kafka Broker 都需要提供证书,双方都必须验证对方的身份。
作用:
配置:
Kafka Broker 配置:
listeners=SSL://0.0.0.0:9093
advertised.listeners=SSL://your-broker-hostname:9093
ssl.keystore.location=/path/to/kafka.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/path/to/kafka.truststore.jks
ssl.truststore.password=changeit
# 启用客户端认证
ssl.client.auth=required
security.inter.broker.protocol=SSL
生产者/消费者配置:
security.protocol=SSL
ssl.truststore.location=/path/to/kafka.truststore.jks
ssl.truststore.password=changeit
ssl.keystore.location=/path/to/kafka.client.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
具体事例:
假设你在处理金融行业的敏感数据,Kafka 集群中传输的信息涉及到客户的个人数据或支付信息,必须确保只有授权的客户端可以连接到 Kafka 集群,并且数据传输过程中必须加密。此时,你可以配置 SSL 双向认证,要求每个客户端提供有效的证书,确保只有合法的客户端和 Broker 能建立连接。
配置类型 | 加密 | 身份验证 | 使用场景 | 配置复杂度 | 性能影响 |
---|---|---|---|---|---|
PLAINTEXT | 无加密 | 无身份验证 | 开发环境或非生产环境,安全要求不高 | 最简单 | 性能最佳 |
SSL(单向认证) | 数据加密 | 仅验证 Broker 身份 | 企业内部数据传输,保护数据加密,验证 Broker 身份 | 中等 | 性能较好 |
SSL(双向认证) | 数据加密 | 验证 Broker 和 客户端 身份 | 高安全性需求场景,如金融、医疗数据传输 | 最复杂 | 性能稍差 |
选择合适的 SSL 配置要根据实际的安全需求和性能要求来决定。如果安全性较高的要求可以容忍性能的轻微下降,建议选择 双向认证。如果性能要求较高且安全性要求较低, 单向认证 是一个合适的选择。
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
错误通常表示SSL/TLS握手过程出现问题,导致客户端和Kafka服务器无法成功建立安全连接。这个错误常见的原因包括证书问题、TLS版本不匹配、加密套件不匹配等。
最常见的原因之一是客户端与服务器之间的证书不匹配。可能是客户端未能正确验证服务器的证书,或者服务器证书不符合要求。
具体问题及解决方案:
证书过期:如果证书过期,握手失败。
证书链不完整:如果Kafka服务器的证书未正确配置中间证书链,也会导致握手失败。
使用以下命令检查证书链:
openssl s_client -connect kafka-server:9093 -showcerts
信任库问题:客户端没有信任Kafka服务器的证书。
truststore
包含Kafka服务器证书或CA根证书。在客户端配置中指定truststore
路径:
ssl.truststore.location=/path/to/truststore.jks
ssl.truststore.password=yourpassword
Kafka服务器和客户端可能支持不同的TLS版本。如果客户端使用的TLS版本不被服务器支持,握手会失败。
具体问题及解决方案:
Kafka默认支持TLSv1.2,但某些较旧的客户端可能只支持TLSv1.1或更早版本,导致版本不兼容。
确保服务器和客户端都支持相同的TLS版本:
在server.properties
中启用TLSv1.2,禁用不安全的版本:
ssl.enabled.protocols=TLSv1.2
客户端也需要确保配置了相同的TLS版本。
对于Java客户端,可以通过以下方式设置TLS版本:
-Dhttps.protocols=TLSv1.2
Kafka和客户端使用的加密算法套件(cipher suites)不同,也会导致握手失败。
具体问题及解决方案:
加密套件不匹配:Kafka服务器和客户端之间的加密算法套件不同。
可以在Kafka服务器配置中指定支持的加密套件:
ssl.cipher.suites=TLS_RSA_WITH_AES_128_CBC_SHA
确保客户端使用支持的加密算法套件。
Kafka的server.properties
和客户端的配置可能不匹配,或者配置不完整。
具体问题及解决方案:
确保Kafka服务器启用了SSL并正确配置了相关属性:
listeners=SSL://localhost:9093
listener.security.protocol=SSL
ssl.keystore.location=/path/to/kafka.keystore.jks
ssl.keystore.password=keystore-password
ssl.key.password=key-password
ssl.truststore.location=/path/to/kafka.truststore.jks
ssl.truststore.password=truststore-password
客户端连接配置也需要正确设置SSL:
security.protocol=SSL
ssl.truststore.location=/path/to/client.truststore.jks
ssl.truststore.password=truststore-password
客户端与服务器使用的Java版本不同,有时会导致SSL/TLS握手失败。较老的Java版本可能不支持新版本的TLS协议。
具体问题及解决方案:
CertificateExpiredException: NotAfter: Mon Jan 1 00:00:00 UTC 2025
这个错误意味着 Kafka 使用的 SSL 证书已经过期。NotAfter
字段指明了证书的有效期,超出这个日期后,证书会被认为是无效的。
在这种情况下,Kafka 客户端和服务器会因为无法验证 SSL 证书的有效性而发生连接失败。
SSL/TLS证书通常有有效期,过了有效期之后,证书就不再被信任。如果 Kafka 的 SSL 证书过期,那么它会导致 CertificateExpiredException
异常。
错误消息类似如下:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Caused by: javax.net.ssl.SSLException: CertificateExpiredException: NotAfter: Mon Jan 1 00:00:00 UTC 2025
这里,NotAfter
指的是证书的过期时间。
要解决这个问题,您需要更新过期的证书。以下是具体步骤:
步骤 1:检查证书过期时间
首先,您需要检查 Kafka 使用的证书的过期时间。可以通过以下命令查看证书的有效期:
openssl x509 -in /path/to/your/certificate.crt -noout -dates
例如,输出可能类似于:
notBefore=Sep 1 00:00:00 2023 GMT
notAfter=Jan 1 00:00:00 2025 GMT
这表示证书有效期是从 2023 年 9 月 1 日开始,到 2025 年 1 月 1 日结束。
步骤 2:更新证书
如果证书已经过期,您需要获取一个新的有效证书。
如果您使用的是 自签名证书,则需要重新生成新的证书。
生成新证书的命令:
openssl req -new -x509 -keyout kafka.key -out kafka.crt -days 3650
如果您使用的是由 CA(证书颁发机构) 签发的证书,您需要联系 CA 并申请更新证书。
步骤 3:替换证书并重启 Kafka
一旦您有了新的有效证书,您需要将其替换旧证书。
将新的证书(例如 kafka.crt
)和密钥文件(例如 kafka.key
)放置到正确的路径上。
修改 server.properties
中 SSL 配置路径:
ssl.keystore.location=/path/to/new/kafka.keystore.jks
ssl.key.password=yourkeypassword
ssl.keystore.password=yourkeystorepassword
ssl.truststore.location=/path/to/new/kafka.truststore.jks
ssl.truststore.password=yourtruststorepassword
重启 Kafka 服务器:
bin/kafka-server-start.sh config/server.properties
步骤 4:检查客户端的证书
如果客户端使用 SSL 连接 Kafka,客户端也需要更新信任的证书。确保客户端的 truststore
包含新的 Kafka 证书。
场景 1:证书过期导致连接失败
假设 Kafka 使用的是自签名证书,并且证书有效期为一年。当到了 2025 年 1 月 1 日,证书过期时,Kafka 客户端尝试连接时,会抛出 CertificateExpiredException
错误。
错误日志:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Caused by: javax.net.ssl.SSLException: CertificateExpiredException: NotAfter: Mon Jan 1 00:00:00 UTC 2025
解决过程:
openssl
命令确认证书的有效期。truststore
,确保信任新的证书。场景 2:CA 签发的证书过期
假设 Kafka 使用的是由 CA 签发的证书,该证书的有效期为 2 年。到了证书的过期日期(例如 2025 年 1 月 1 日),所有尝试连接 Kafka 的客户端都会遇到握手失败的问题。
错误日志:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Caused by: javax.net.ssl.SSLException: CertificateExpiredException: NotAfter: Mon Jan 1 00:00:00 UTC 2025
解决过程:
No X509TrustManager implementation available
错误通常发生在使用 SSL/TLS 连接时,Java 客户端无法找到或加载适当的 X509TrustManager
实现。X509TrustManager
是 Java 用来管理和验证 SSL 证书的类。如果没有适当的实现,SSL 握手就会失败,导致 Kafka 生产者或消费者无法连接。
该错误的常见原因包括:
SunJSSE
)。如果这些提供程序未正确加载或被禁用,就会出现 No X509TrustManager implementation available
错误。truststore
) 来验证服务器证书。如果客户端无法加载或访问信任库,也会导致该错误。X509TrustManager
。Java 默认使用 SunJSSE
安全提供程序来处理 SSL 连接。如果该提供程序被禁用或无法加载,就会出现该错误。
检查 Java 安装和安全提供程序:
确保 Java 安装没有损坏,并且包含了 SunJSSE
提供程序。可以通过以下命令查看当前 Java 安装的安全提供程序:
java -jar /path/to/java/jre/lib/security/cacerts
检查 JVM 配置:
确保 JVM 配置没有禁用 SunJSSE
或其它安全提供程序。可以通过 java.security
文件配置来确认:
$JAVA_HOME/jre/lib/security/java.security
如果 Kafka 客户端(生产者或消费者)需要与启用了 SSL 的 Kafka 集群连接,需要确保 SSL 配置正确,包括提供信任库(truststore
)。
示例配置(producer.properties
或 consumer.properties
):
security.protocol=SSL
ssl.truststore.location=/path/to/kafka.client.truststore.jks
ssl.truststore.password=yourtruststorepassword
ssl.keystore.location=/path/to/kafka.client.keystore.jks
ssl.keystore.password=yourkeystorepassword
ssl.key.password=yourkeypassword
ssl.endpoint.identification.algorithm=
ssl.truststore.location
指定信任库路径,包含Kafka服务器证书或CA证书。ssl.keystore.location
指定客户端证书路径(如果Kafka需要客户端证书)。ssl.endpoint.identification.algorithm
可以设置为空字符串以禁用主机名验证(不推荐生产环境使用)。如果 Kafka 客户端未能找到正确的信任库,它将无法验证服务器证书,从而抛出 No X509TrustManager implementation available
错误。
使用 keytool
命令检查 Java 信任库:
查看当前 Java 安装是否有信任库,运行以下命令:
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
创建和配置信任库:
如果没有信任库,可以使用 keytool
从 Kafka 服务器的证书创建信任库:
keytool -importcert -file /path/to/kafka-server-cert.pem -keystore /path/to/kafka.client.truststore.jks -alias kafka-server -storepass yourtruststorepassword
在 JVM 启动时指定信任库:
java -Djavax.net.ssl.trustStore=/path/to/kafka.client.truststore.jks -Djavax.net.ssl.trustStorePassword=yourtruststorepassword
某些旧版本的 Java 可能会导致 SSL 连接的问题,特别是在对 X509TrustManager
和 JSSE
(Java Secure Socket Extension)支持方面的实现不完整。
建议使用较新的 Java 版本:至少是 Java 8u151 或更高版本,因为这些版本解决了许多 SSL 相关的缺陷。
检查 Java 版本:
java -version
Kafka 服务器配置也需要正确,以便与启用 SSL 的客户端进行通信。
server.properties
):listeners=SSL://kafka-server:9093
listener.security.protocol=SSL
ssl.keystore.location=/path/to/kafka.server.keystore.jks
ssl.keystore.password=yourkeystorepassword
ssl.key.password=yourkeypassword
ssl.truststore.location=/path/to/kafka.server.truststore.jks
ssl.truststore.password=yourtruststorepassword
案例 1:缺少信任库导致的错误
No X509TrustManager implementation available
错误。truststore
配置正确,包含 Kafka 服务器的证书或 CA 根证书。keytool
导入服务器证书到客户端的信任库。案例 2:Java 安装问题
No X509TrustManager implementation available
错误,检查后发现是 Java 安装中的 SunJSSE
提供程序缺失。SunJSSE
提供程序。SunJSSE
被禁用,修改 java.security
配置文件启用它。