SASL 认证机制:从 PLAIN 到 Kerberos 的实战选择

说到 Kafka 的认证,SASL 是个绕不开的话题。我最早接触它的时候,也被那一堆缩写搞得头大——PLAIN、SCRAM、GSSAPI,到底该用哪个?

其实 SASL 全称是 Simple Authentication and Security Layer,说白了就是一个认证框架。它不负责具体怎么验证身份,而是定义了一套接口,让不同的认证机制可以插进去用。Kafka 支持三种主流机制:PLAIN、SCRAM 和 GSSAPI(Kerberos)。

今天我就把这三种机制掰开揉碎了讲清楚。你想想看,选错了认证方式,后面运维起来有多痛苦?我踩过的坑,你就别踩了。

一句话总结:PLAIN 适合快速验证环境,SCRAM 是生产环境的首选,Kerberos 适合已经部署了 Kerberos 的大企业。

SASL 认证机制对比总览 SASL/PLAIN 用户名+密码明文传输 静态文件存储密码 不支持动态增删用户 SASL/SCRAM 密码不传输,挑战-响应 ZooKeeper 存储凭证 支持动态增删用户 SASL/GSSAPI Kerberos 票据认证 需要 KDC 基础设施 企业级安全最高 选择建议 开发测试用 PLAIN → 生产环境用 SCRAM → 已有 Kerberos 基础设施用 GSSAPI 配置复杂度:低 安全性:低 配置复杂度:中 安全性:高 配置复杂度:高 安全性:最高

SASL/PLAIN:最简单的方案,但别用在生产环境

SASL/PLAIN 是三种机制里最直白的。客户端把用户名和密码直接发给 Broker,Broker 拿着配置文件里的信息做比对。嗯,就是明文传输,没有加密。

我记得刚入行那会儿,有个同事图省事,直接在线上环境配了 PLAIN。结果安全审计的时候被查出来,差点背了处分。后来我养成了一个习惯:PLAIN 只用来做功能验证,上线前必须换掉。

配置步骤

  1. 创建 JAAS 配置文件:在每台 Broker 上创建 kafka_server_jaas.conf
  2. 配置 Broker:修改 server.properties 启用 SASL_PLAINTEXT 监听器
  3. 配置客户端:生产者和消费者也需要 JAAS 配置

来看一个具体的 Broker 端 JAAS 配置:

KafkaServer {
  org.apache.kafka.common.security.plain.PlainLoginModule required
  username="admin"
  password="admin-secret"
  user_admin="admin-secret"
  user_producer="producer-secret"
  user_consumer="consumer-secret";
};

注意:这里的密码是明文存储的。一旦配置文件泄露,所有账号就全完了。我曾经见过有人把 JAAS 文件提交到 Git 仓库里……嗯,那场面,不堪回首。

Broker 端 server.properties 的改动:

listeners=SASL_PLAINTEXT://0.0.0.0:9093
advertised.listeners=SASL_PLAINTEXT://broker1.example.com:9093
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN
authorizer.class.name=kafka.security.authorizer.AclAuthorizer

客户端配置就简单多了:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
  username="producer" \
  password="producer-secret";

我的建议:如果你非要在开发环境用 PLAIN,至少把监听器绑定到内网 IP,别暴露到公网。另外,密码别用 admin/admin123 这种,我见过太多人这么干了。

SASL/SCRAM:生产环境的正确选择

SCRAM 全称是 Salted Challenge Response Authentication Mechanism。名字很长,但核心思想很简单:密码不在网络上传输。

客户端和 Broker 之间通过一系列挑战-响应交互来验证身份。即使有人抓包,也拿不到密码原文。而且 SCRAM 支持动态增删用户,不用重启 Broker。

我个人习惯在生产环境首选 SCRAM。它比 PLAIN 安全得多,配置起来又比 Kerberos 简单。性价比最高。

SCRAM 的工作原理

我画个简单的流程帮你理解:

  1. 客户端发起认证请求,带上用户名
  2. Broker 返回一个随机挑战(包含 salt 和迭代次数)
  3. 客户端用密码和挑战计算响应值,发回 Broker
  4. Broker 用自己存储的凭证验证响应值

整个过程密码只在客户端内存里出现一次,网络传输的全是计算后的摘要。

配置步骤

第一步,在 ZooKeeper 里创建用户凭证:

# 创建管理员用户
kafka-configs.sh --zookeeper localhost:2181 \
  --alter --add-config 'SCRAM-SHA-256=[password=admin-secret]' \
  --entity-type users --entity-name admin

# 创建生产者用户
kafka-configs.sh --zookeeper localhost:2181 \
  --alter --add-config 'SCRAM-SHA-512=[password=producer-secret]' \
  --entity-type users --entity-name producer

关键点:SCRAM 凭证存储在 ZooKeeper 中,所以 ZooKeeper 本身也要做好安全防护。我见过有人 ZooKeeper 没配认证,结果 SCRAM 凭证被人直接删了……

第二步,Broker 端 JAAS 配置:

KafkaServer {
  org.apache.kafka.common.security.scram.ScramLoginModule required
  username="admin"
  password="admin-secret";
};

注意看,这里只需要配置 Broker 自身用于 Broker 间通信的凭证。用户的凭证已经在 ZooKeeper 里了。

第三步,server.properties 配置:

listeners=SASL_PLAINTEXT://0.0.0.0:9093
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-512
sasl.enabled.mechanisms=SCRAM-SHA-256,SCRAM-SHA-512

客户端配置:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=SCRAM-SHA-512
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
  username="producer" \
  password="producer-secret";

经验之谈:我建议用 SCRAM-SHA-512,别用 SCRAM-SHA-256。虽然 256 也够用,但 512 的哈希更长,暴力破解更难。而且性能开销差别几乎可以忽略不计。

动态管理用户

这是 SCRAM 最大的优势。不用重启 Broker,直接加用户:

# 新增用户
kafka-configs.sh --zookeeper localhost:2181 \
  --alter --add-config 'SCRAM-SHA-512=[password=newuser-secret]' \
  --entity-type users --entity-name newuser

# 删除用户
kafka-configs.sh --zookeeper localhost:2181 \
  --alter --delete-config 'SCRAM-SHA-512' \
  --entity-type users --entity-name olduser

# 查看用户
kafka-configs.sh --zookeeper localhost:2181 \
  --describe --entity-type users --entity-name producer

SASL/GSSAPI(Kerberos):企业级的安全堡垒

Kerberos 是这三者里最复杂的,也是安全性最高的。它基于票据(Ticket)的认证方式,不需要在网络上传送密码。

我在一家金融公司做过项目,他们要求必须用 Kerberos。说实话,配置过程确实折腾,但一旦跑起来,运维反而省心——因为用户管理交给了 KDC,Kafka 这边只管验证票据就行。

Kerberos 的核心概念

组件 作用
KDC 密钥分发中心,负责发放票据
Principal 每个服务的唯一身份标识,格式:service/host@REALM
Keytab 存储 Principal 密钥的文件,相当于密码的替代品
Ticket 临时凭证,有过期时间

配置步骤(精简版)

Kerberos 的配置步骤比较多,我挑核心的讲:

  1. 在 KDC 上创建 Principal:为每台 Broker 和每个客户端创建 Principal
  2. 导出 Keytab 文件:分发到对应的 Broker 和客户端机器
  3. 配置 Broker 端 JAAS:使用 keytab 登录
  4. 配置 krb5.conf:指定 KDC 地址和 Realm 信息

Broker 端 JAAS 配置示例:

KafkaServer {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  storeKey=true
  keyTab="/etc/security/keytabs/kafka.keytab"
  principal="kafka/broker1.example.com@EXAMPLE.COM";
};

server.properties 配置:

listeners=SASL_PLAINTEXT://0.0.0.0:9093
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=GSSAPI
sasl.enabled.mechanisms=GSSAPI
sasl.kerberos.service.name=kafka

我曾经踩过的坑:Principal 的 service name 必须和 sasl.kerberos.service.name 一致。默认是 kafka,如果你改了,两边都要同步改。还有,所有 Broker 的时钟必须同步,Kerberos 对时间偏差很敏感,超过 5 分钟就会认证失败。

客户端配置:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=GSSAPI
sasl.kerberos.service.name=kafka
sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required \
  useKeyTab=true \
  storeKey=true \
  keyTab="/etc/security/keytabs/producer.keytab" \
  principal="producer@EXAMPLE.COM";

三种机制的对比总结

特性 SASL/PLAIN SASL/SCRAM SASL/GSSAPI
密码传输 明文 不传输 不传输
密码存储 配置文件明文 ZooKeeper 加盐哈希 KDC 管理
动态增删用户 不支持,需重启 支持,无需重启 支持,通过 KDC
配置复杂度 低 中 高
运维成本 低 中 高(需维护 KDC)
适用场景 开发测试 生产环境首选 已有 Kerberos 的企业

我的最终建议:如果你在搭建新的 Kafka 集群,直接上 SCRAM-SHA-512。别犹豫。PLAIN 只用来做快速验证,Kerberos 除非公司已经部署了,否则别自己从头搭——那是个无底洞。