当我们与银行和大型企业合作时,Kafka 很少是一个全新起步的话题。

更常见的情况是,Kafka 已经运行了多年。团队依赖它,关键数据在其中流动,平台也积累了大量运维决策、命名约定、服务账号、topic 模式以及访问规则的历史沉淀。等到一个组织决定迁移到 Confluent Platform 时,Kafka 早已不只是一个消息系统,而是生产骨干的一部分。

这一背景很重要,因为在这类环境中,迁移不仅仅是技术项目,更是风险管理工作。

在 Confluent 迁移的第一阶段,最安全的做法通常是尽可能少做改动。目标是先迁移平台基础、让它稳定下来,然后才引入更大的改进。认证与授权也是这个故事的一部分。现有的 Kafka 安装往往依赖 Apache Kafka ACL,因为 ACL 是开源 Kafka 中内置的授权模型。

不过,Confluent Platform 还提供了 RBAC:基于角色的访问控制。在组织规模上,RBAC 通常更易于理解,更契合平台治理,并能自然地与其他 Confluent 组件集成,例如 Metadata Service、Control Center 以及 Confluent for Kubernetes。

于是问题就变成:如何在不把访问控制变成高风险手工迁移的前提下,将一个现有的、基于 ACL 的 Kafka 资产迁移到 Confluent RBAC?

这正是我们构建 monedula-acl-rbac-converter 的原因。

为什么 ACL 到 RBAC 的迁移比看上去更难

一个只有少量 topic 和用户的小型 Kafka 集群可以手工迁移。你检查 ACL,确定对应的 RBAC 角色,创建绑定,验证访问,再移除旧的 ACL。

但大多数成熟的企业环境并不是这个样子。

在真实的部署中,你可能会遇到成百上千条 ACL 规则。有些由平台团队创建,有些由应用团队创建,有些来自自动化,有些虽然很旧但仍在使用,有些使用带前缀的 topic 模式,有些引用的是早已被重命名的服务用户,还有些是从多年无人触碰的脚本里导出的。

在这种情况下,手工迁移存在若干问题:

  • 速度慢,
  • 容易出错,
  • 难以审查,
  • 难以重复,
  • 难以审计,
  • 而且一旦开始清理就会变得危险。

创建新的 RBAC 绑定只是迁移的一半。更微妙的部分是证明新的绑定提供了与旧 ACL 相同的有效访问,然后才移除源 ACL。

正因如此,我们并不想要一个只是「翻译文件」的工具。我们想要的是一套迁移工作流。

转换器做什么

monedula-acl-rbac-converter 是一个命令行工具,它读取现有的 Kafka ACL,将其转换为 Confluent RBAC 角色绑定计划,并帮助运维人员以受控、可审计的方式执行迁移。

它可以从多种真实世界的来源读取 ACL,包括:

  • 一个运行中的 Kafka 集群,
  • 导出的 kafka-acls.sh --list 输出,
  • JSON、YAML 或 CSV 转储文件,
  • Strimzi KafkaUser 清单,
  • Confluent for Kubernetes 清单,
  • 一个运行中的 Kubernetes 集群,
  • 或者一个包含 kafka-acls --add ... 命令的 shell 脚本。

最后这种情况在棕地(brownfield)环境中尤为有用。许多团队并不是从一份干净的导出开始的。相反,他们手里有一个最初创建这些 ACL 的旧安装脚本。

例如,输入脚本中可能包含这样的命令:

kafka-acls.sh \
  --bootstrap-server kafka.example.com:9093 \
  --command-config admin.properties \
  --add \
  --allow-principal User:svc-billing \
  --operation Read \
  --topic billing.events \
  --group billing-consumer

kafka-acls.sh \
  --bootstrap-server kafka.example.com:9093 \
  --command-config admin.properties \
  --add \
  --allow-principal User:svc-billing \
  --operation Describe \
  --topic billing.events

转换器可以将这些 ACL 定义提取到一个规范化的 acls.json 文件中。从这里出发,它能生成一份经过审查的迁移计划、输出脚本或清单、将绑定直接应用到 Confluent MDS、验证结果,并为旧 ACL 生成清理脚本。

为高风险变更而设计的工作流

访问控制迁移需要护栏。一个错误的权限可能会破坏生产工作负载。一个过于宽泛的权限可能会引发安全事件。一个执行得过早的清理步骤可能会导致服务中断。

正因如此,生产工作流是明确的、分步骤的:

1. extract       -> 创建规范化 ACL 快照
2. plan          -> 将 ACL 转换为 RBAC 迁移计划
3. apply dry-run -> 预览 MDS 变更
4. apply         -> 创建 RBAC role bindings
5. verify        -> 检查有效访问权限
6. wait          -> 让用户验证新路径
7. delete-acls   -> 为旧 ACL 生成删除脚本
8. review + run  -> 手动执行清理

每一步都会生成可被检查、审查、版本化或附加到变更请求中的产物。

该工具有意将计划与应用分离、将应用与验证分离、将验证与删除分离。这使得迁移更易于理解,在受监管的环境中运行也更安全。

示例:从一个 ACL 安装脚本迁移

假设起点是一个包含 kafka-acls.sh --add 命令的 shell 脚本。

1. 提取 ACL

首先,将 ACL 提取为一个规范化的 JSON 表示:

monedula-acl-rbac extract \
  --from script \
  --input setup-acls.sh \
  --vars vars.yaml \
  --out runs/billing-batch-1/acls.json

当脚本中包含变量时,可选的 vars.yaml 文件就很有用。该工具不会去猜测未解析的值。如果存在变量,应当显式提供它们,或者在迁移前先把脚本展开。

在这个阶段,输出仍然只是一个快照。没有任何外部状态被改变。

2. 创建迁移计划

接下来,将提取出的 ACL 转换为一个角色绑定计划:

monedula-acl-rbac plan \
  --acls runs/billing-batch-1/acls.json \
  --scopes scopes.yaml \
  --rules rules.yaml \
  --principals principals.yaml \
  --out runs/billing-batch-1/plan.json

scopes.yaml 文件标识了 RBAC 绑定应针对的 Confluent 集群。可选的 rules.yaml 和 principals.yaml 文件让运维人员能够使转换适应自己的环境,例如将源 principal 映射到 MDS 所期望的 principal 格式。

计划步骤还会生成一份报告。这是整个工作流中最重要的审查点之一。它展示了每条源 ACL 变成了什么,并标记出任何无法映射或不应自动转换的内容。

3. 阅读报告

在应用任何内容之前,运维人员应当阅读生成的报告。

正是在这里,迁移工作变得可见。团队不必依赖一个黑盒式的转换,而是可以审查生成的绑定、调查未映射的 ACL,并决定是否需要自定义映射规则。

DENY 类型的 ACL 值得特别关注。Confluent RBAC 没有等价的拒绝语义,因此 DENY ACL 不会被悄无声息地转换。它们会被报告出来并单独处理。

4. 对应用步骤进行 dry-run

在 MDS 中创建角色绑定之前,先运行一次 dry-run:

monedula-acl-rbac apply \
  --plan runs/billing-batch-1/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --dry-run

dry-run 会预览将要进行的 MDS 调用。它还会执行读取检查,以便可以幂等地跳过已存在的绑定。

这为运维人员在第一次真正变更之前提供了又一个检查点。

5. 应用 RBAC 绑定

在审查过 dry-run 输出之后,应用该计划:

monedula-acl-rbac apply \
  --plan runs/billing-batch-1/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --confirm

应用步骤会在 Confluent MDS 中创建 RBAC 绑定。它被设计为可重复运行:如果某个绑定已存在,就会被跳过。

6. 验证有效访问

在应用 RBAC 绑定之后,验证它们确实授予了 ACL 最初提供的访问权限:

monedula-acl-rbac verify \
  --plan runs/billing-batch-1/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token

这比检查某个绑定是否存在更为有力。其目标是确认原始 principal、operation 和资源的有效访问。

这一区别在企业环境中尤为重要,因为身份传播、组成员关系、LDAP 集成或 scope 不匹配都可能导致一个绑定虽然存在却没有按预期工作。

7. 生成 ACL 删除脚本

只有在验证成功之后,并且经过运维人员定义的冷却期之后,才应移除源 ACL。

该工具不会直接删除 ACL。相反,它会生成一个由运维人员自行检查并运行的脚本:

monedula-acl-rbac delete-acls \
  --plan runs/billing-batch-1/plan.json \
  --verify runs/billing-batch-1/verify.json \
  --bootstrap-server kafka.example.com:9093 \
  --command-config admin.properties \
  --principal User:svc-billing \
  --confirm \
  --i-understand-this-is-destructive

生成的产物包括:

delete-acls.sh
deleted-acls.json
rollback.sh

这是一个有意设置的人工检查点。运维人员可以打开脚本,审查每一条 kafka-acls --remove 命令,逐个 principal 地运行它,并在迁移稳定之前一直保留回滚脚本。

针对不同运维模式的不同输出

并非每个组织都想要相同的应用模式。

有些团队乐于直接应用到 MDS。另一些团队则需要每一次变更都经过变更控制流程、GitOps 流程或外部 CD 流水线。

转换器通过输出不同类型的产物来支持这些场景:

# 包含 Confluent CLI role-binding 命令的 shell 脚本
monedula-acl-rbac emit \
  --plan runs/billing-batch-1/plan.json \
  --format script \
  --out-dir emit/

# Confluent for Kubernetes 清单
monedula-acl-rbac emit \
  --plan runs/billing-batch-1/plan.json \
  --format cfk \
  --out-dir emit/

# 面向 MDS REST API 的 curl 命令
monedula-acl-rbac emit \
  --plan runs/billing-batch-1/plan.json \
  --format mds-curl \
  --out-dir emit/

这使得该工具既适用于动手实操的迁移工作,也适用于那些基础设施变更必须通过独立审批与部署系统的环境。

为真实迁移中的混乱而构建

我们尽力去支持那些在实际 Kafka 资产中会出现的输入和约束,而不仅仅是干净的演示场景。

这包括:

  • 实时 Kafka 提取,
  • 文本导出,
  • 结构化文件,
  • Kubernetes 原生资源,
  • 现有的 Confluent for Kubernetes 清单,
  • 旧的安装脚本,
  • principal 重映射,
  • 自定义转换规则,
  • dry-run 执行,
  • 直接 MDS 应用,
  • 输出的脚本和清单,
  • 有效访问验证,
  • 删除脚本生成,
  • 回滚产物,
  • 以及用于可重复迁移批次的 status/diff 命令。

最终得到的是一款既可用于探索、又可用于生产级迁移的工具。

对于小型实验,一次性的 convert 命令可以在单个步骤中完成提取、计划和脚本输出:

monedula-acl-rbac convert \
  --from yaml \
  --input acls.yaml \
  --scopes scopes.yaml \
  --rules rules.yaml \
  --principals principals.yaml \
  > bindings.sh

对于生产环境,推荐采用明确的流水线路径,因为它能保留审计产物和审查点。

结语

从 Kafka ACL 迁移到 Confluent RBAC 不只是一个语法转换问题。

它是对一个运行中的数据平台授权模型的一次受控变更。在大型组织中,尤其是在银行业和受监管行业里,这种变更需要是可审查、可重复、可审计的,并且在可能的情况下是可逆的。

我们构建 monedula-acl-rbac-converter,是因为我们不断看到同样的模式:Kafka 早已就位,ACL 早已就位,而团队希望在迁移压力之下采用 Confluent RBAC,却不必手工翻译成百上千条规则。

这款工具的目的不是隐藏迁移过程,而是让它变得可见。

提取当前状态。规划目标状态。审查报告。Dry-run 变更。审慎地应用。验证有效访问。生成清理脚本。审查它们。然后,只有在你准备好时,才移除旧的 ACL。

这正是我们希望访问控制迁移所采用的那种工作流。

我们构建它,是因为它对我们有用。我们也希望它对其他人同样有用。

你可以在 GitHub 上找到 monedula-acl-rbac-converter。如果你发现了 bug 或有改进建议,欢迎提交 issue。

工具: monedula-acl-rbac-converter 有支持的输入格式、计划输出和仓库。