当我们与银行和大型企业合作时,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.yamlprincipals.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。