> 文章列表 > kafka 构建双向SSL认证

kafka 构建双向SSL认证

kafka 构建双向SSL认证

kafka 安装

以下内容均已完成测试,按照教程搭建你会得到一个双向ssl认证的kafka broker,并能通过ip以及域名访问,笔者能力有限如果文章内容存在问题烦请各位指出。

搭建单机Kafka

需求

  • centos 7
  • kafka_2.12-2.6.0
  • jdk8+(文档中统一使用jdk1.8.0_202)

安装

参考文档

安装路径:/opt/kafka_2.12-2.6.0

步骤1:获取Kafka

wget https://archive.apache.org/dist/kafka/2.6.0/kafka-2.6.0-src.tgz
tar -xzf kafka_2.12-2.6.0.tgz
cd kafka_2.12-2.6.0  

步骤2:启动kafka环境

# 启动zookeeper 服务
bin/zookeeper-server-start.sh config/zookeeper.properties
# 启动kafka broker 服务
bin/kafka-server-start.sh config/server.properties
# 创建topic,用于后续测试
bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092

至此kafka 已经安装并启动成功,以下围绕service.properties配置双向ssl展开

签发双向SSL

需求

  • keytool jdk8+(文档中统一使用jdk1.8.0_202)
  • openssl 1.0.2k-fips

参考文档

kafka官方文档
kafka官方文档-译文
keytool官方文档
openssl官方文档

实现步骤

注🚩:

  • COMMON NAME😅: 配置keystore时的cn选项表示COMMON NAME,客户端就会校验证书的【COMMON NAME】与机器的”域名“,如下方-dname "cn=mykafkassl.com,ou=xxx"中,主机名设置为了 mykafkassl.com,那么在建立ssl连接就应该使用SSL://mykafkassl.com:<port>,如果直接使用ip会提示主机名校验失败或者握手失败的错误。
  • SAN(更好的方式)😁: COMMON NAME的局限性很明显,只能使用单个域名,无法给多个域名以及IP签名,针对此种情况可以配置SAN(Subject Alternative Name)解决。自从SAN引入以来,使用COMMON NAME就变得比不那么可取,尽管它还可以用。

步骤1: 构造keystore

构造密钥目录

mkdir /var/private/ssl -p
cd /var/private/ssl

-dname 选项请按照实际情况修改,应十分注意cn的内容,这会直接影响证书是否可用
-validity 为有效期
-keyalg 表示选项指定生成密钥对或私钥时使用的算法,默认为DSA,使用默认选项会出现jks转成pem私钥解析失败的问题

keytool -genkey -dname "cn=mykafkassl.com, ou=qihoo, o=qihoo, c=CN" -keystore server.keystore.jks -alias localhost -validity 36500 -storetype PKCS12 -keypass <your password> -storepass <your password> -keyalg RSAkeytool -genkey -dname "cn=mykafkassl.com, ou=qihoo, o=qihoo, c=CN" -keystore client.keystore.jks -alias localhost -validity 36500 -storetype PKCS12 -keypass <your password> -storepass <your password> -keyalg RSA

步骤2: 生成CA签发机构

生成CA的私钥、CA的证书

提示内容请根据实际情况填写,COMMON NAME 部分建议与步骤一保持一致
-days选项表示有效期

openssl req -new -x509 -keyout ca-key -out ca-cert -days 36500

步骤3: 使用CA给证书签名

导出证书以便于后续签名

# server
keytool -keystore server.keystore.jks -alias localhost -certreq -file server.crt -keypass <your password> -storepass <your password># client
keytool -keystore client.keystore.jks -alias localhost -certreq -file client.crt -keypass <your password> -storepass <your password>

使用步骤2生成的CA给刚导出的证书签名

openssl.cnf 用于构造SAN,需要根据实际情况修改[alt_names]

[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = MN
localityName = Locality Name (eg, city)
localityName_default = Minneapolis
organizationalUnitName  = Organizational Unit Name (eg, section)
organizationalUnitName_default  = Domain Control Validated
commonName = Internet Widgits Ltd
commonName_max  = 64[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names[alt_names]
DNS.1 = mykafkassl.com
IP.1 = <your ip address>

将openssl.cnf 拷贝到服务器上

# server
openssl x509 -req -CA ca-cert -CAkey ca-key -in server.crt -out server-crt.signed -days 36500 -CAcreateserial -extfile openssl.cnf -extensions v3_req# client
openssl x509 -req -CA ca-cert -CAkey ca-key -in client.crt -out client-crt.signed -days 36500 -CAcreateserial -extfile openssl.cnf -extensions v3_req

步骤4: 将签名后的证书和CA证书导入到keystore

# server
keytool -keystore server.keystore.jks -alias CARoot -import -file ca-cert -keypass <your password> -storepass <your password>
keytool -keystore server.keystore.jks -alias localhost -import -file server-crt.signed -keypass <your password> -storepass <your password># client
keytool -keystore client.keystore.jks -alias CARoot -import -file ca-cert -keypass <your password> -storepass <your password>
keytool -keystore client.keystore.jks -alias localhost -import -file client-crt.signed -keypass <your password> -storepass <your password>

步骤5:构造信任库

# server
keytool -keystore server.truststore.jks -alias CARoot -import -file ca-cert -keypass <your password> -storepass <your password># client
keytool -keystore client.truststore.jks -alias CARoot -import -file ca-cert -keypass <your password> -storepass <your password>

步骤6:配置server.properties

vim /opt/kafka_2.12-2.6.0/config/server.properties
security.inter.broker.protocol=SSLlisteners=SSL://0.0.0.0:9093advertised.listeners=SSL://<your ip address>:9093ssl.keystore.location=/var/private/ssl/server.keystore.jks
ssl.keystore.password=Q!hooS0c
ssl.key.password=Q!hooS0cssl.truststore.location=/var/private/ssl/server.truststore.jks
ssl.truststore.password=Q!hooS0c
ssl.enabled.protocols=TLSv1.2,TLSv1.1,TLSv1ssl.client.auth=required
ssl.endpoint.identification.algorithm=

步骤7:配置客户端测试

生成client-ssl.properties客户端配置

vim /opt/kafka_2.12-2.6.0/config/client-ssl.properties

client-ssl.properties

security.protocol=SSL
ssl.truststore.location=/var/private/ssl/client.truststore.jks
ssl.truststore.password=Q!hooS0cssl.keystore.location=/var/private/ssl/client.keystore.jks
ssl.keystore.password=Q!hooS0c
ssl.key.password=Q!hooS0c

启动客户端,并输入一些测试数据,如果没有报错则表明ssl配置成功

bin/kafka-console-producer.sh --broker-list <your ip address>:9093 --topic quickstart-events --producer.config config/client-ssl.properties
bin/kafka-console-consumer.sh --bootstrap-server <your ip address>:9093 --topic quickstart-events --consumer.config config/client-ssl.properties

ssl 的鉴权原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTsx9w4K-1677863718067)(/uploads/58fcebe11ae36ec898636069d3ef180e/image.png)]

常见问题

问题1:配置ssl 不生效

kafka broker配置了PLAINTEXT和SSL两个端口,客户端通过PLAINTEXT连接没有经过SSL

问题2:使用官方文档的方式验证ssl配置出现error字样

由于是自签名,这种情况属正常现象

问题3:客户端携带证书的tcp请求(消费请求)会提示请求数据过大(默认100m)

请不要盲目参考网络上教程提高max_size,应该仔细检查server.properties 配置

问题4:ssl握手失败

在步骤1中的域名配置错误,在客户端校验时发现主机名与证书的COMMON NAME不一致,故断开连接。
当然 握手失败的的原因远远不止这一种,推荐使用抓包工具(如wireshark、tcpdump)抓包排查握手失败发生在哪一步从而确定错误原因、使用openssl自带的s_client、s_server并开启debug模式,定位错误原因。

问题5:我只有一个ip,没有域名应该怎么签

common name可以配置成一个虚拟的域名,然后再客户端和服务器中修改hosts。也可以配置SAN,在扩展项中输入ip