Kafka安全机制解析(一)

基本架构解析

Posted by Cadmean on July 27, 2018

基本架构

最近开始主攻Kafka,在了解Kafka的功能后,要把Kafka构建成一个企业级的消息平台,首先需要完善的就是安全机制。

Kafka官方提供的客户端与服务端的安全机制有两种,官方的文档上写的很清楚:

  1. SSL协议,一般来说单向SSL协议就够了,双向需要在新增用户时修改服务端的证书还要重启服务器,比较麻烦。这个和ActiveMQ的证书制作类似,可以参考ActiveMQ使用SSL单向认证
  2. SASL认证机制:主要有三种方式(1)基于Kerberos的GSSAPI(2)PLAINTEXT(3)SCRAM。

撇开SSL协议不谈,对SASL认证来说,没有使用Kerberos的公司就别考虑用(1)了,(2)和(3)的区别在于PLAINTEXT模式的用户密码是明文保存在服务端的JAAS配置文件中的,且客户端使用PLAIN时,密码是明文传输(Kafka官方建议通过SSL协议加密);而SCRAM的用户密码是保存在ZOOKEEPER上的,可通过脚本动态增减用户,客户端使用SCRAM模式认证时,密码会经过SHA-256的不可逆加密而后传输到服务端。其实归根结底,我们在做KAFKA安全模块时,需要考虑的是以下几个问题(适用于所有应用):

  • 密码如果在服务端保存,需要密文保存
  • 每次新增用户最好不要重启Broker
  • 客户端密码需要密文传输

业界已有的Kafka平台我看了看,像阿里的消息服务Kafka,腾讯的Ckafka,华为的消息服务DMS也有Kafka。这些互联网大厂都有自己的Kafka安全机制,我主要参考了下阿里和华为的鉴权构件,都是基于Kafka开放出来的鉴权API自己写了一套。所以我也自己试了试,尝试自己重构了一套安全机制。

流程分析

在讲解重构前,我们需要先了解一下KAFKA的SASL认证模式。我大略画了个图。 客户端与服务端鉴权流程

基本的实现逻辑在kafka的clients的包里,是用java写的。客户端主要在类org.apache.kafka.clients common.security.auth.SaslClientAuthenticator中,服务端在org.apache.kafka.clients common.security.auth.SaslServerAuthenticator类中。其中被写死的步骤是1、2两步,第3,4都可以通过重写SaslClient和SaslServer来实现自定义请求交互.

在SaslClient中有一个hasInitialResponse方法,这个方法定义的是客户端和服务端之间的交互是否一次到位,如果设定为false则表示会发送一个空包给服务端,如果设定为true则表示直接发送鉴权信息。INTERMEDIATE阶段可以有多个,也就是支持来回多次的信息交互,这些信息交互都通过才算鉴权通过。

可供我们自己实现的步骤有3,4,那么我们可以实现以下几个功能:

  1. 在客户端构造密文时(第3步前),可以实现自定义的加密模式,比如加盐。我研究了下阿里和华为的源码,他们的做法是构造一个明文串(串中有用户名,还能加上时间戳随机数等花样),然后把明文加上密文一起加密,再将明文串放在加密后的串前,构造出鉴权报文。服务端收到后先通过分割报文解析出明文,然后加上服务端获取到的密码,和明文串一起加密后,再比对客户端传上的密文和自己生成的密文,一致则校验通过。
  2. 服务端的校验可以自己实现,因此我们可以自己实现用户密码的加载,比如去用户中心获取用户信息,或者自己写一个用户密码文件,然后实例化一个单例线程,让其监控文件变化并重新加载,从而解决需要重启broker的问题。
  3. 第4步发送的空包类似于校验的终止符。如果觉得一次校验不够犀利,可以像SCRAM那样多次校验。客户端只要不收到空包,都会继续尝试发送报文。具体可参考SCRAM源码。

今天就到这里吧,下一篇直接上代码,讲解如何重构一个比PLAIN模式更复杂的Kafka安全认证框架。


< script src = " / js / bootstrap.min.js " >