---
title: "从 Kafka ACL 到 Confluent RBAC：借助一款全新开源工具实现安全的迁移路径"
date: 2026-06-17T00:00:00.000Z
author: "michal"
excerpt: "把现有的 Kafka 资产从 ACL 迁移到 Confluent RBAC 是一项风险管理工作，而非语法转换。本文介绍一套安全、可审计、可重复的迁移工作流，以及我们为此构建的工具。"
---
当我们与银行和大型企业合作时，Kafka 很少是一个全新起步的话题。

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

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

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

不过，Confluent Platform 还提供了 [RBAC：基于角色的访问控制](https://docs.confluent.io/platform/current/security/authorization/rbac/overview.html)。在组织规模上，RBAC 通常更易于理解，更契合平台治理，并能自然地与其他 Confluent 组件集成，例如 Metadata Service、Control Center 以及 [Confluent for Kubernetes](https://docs.confluent.io/operator/current/overview.html)。

于是问题就变成：如何在不把访问控制变成高风险手工迁移的前提下，将一个现有的、基于 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 的旧安装脚本。

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

```sh
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 生成清理脚本。

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

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

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

```text
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 表示：

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

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

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

### 2. 创建迁移计划

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

```sh
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：

```sh
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 输出之后，应用该计划：

```sh
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 最初提供的访问权限：

```sh
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。相反，它会生成一个由运维人员自行检查并运行的脚本：

```sh
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
```

生成的产物包括：

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

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

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

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

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

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

```sh
# 包含 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` 命令可以在单个步骤中完成提取、计划和脚本输出：

```sh
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`](https://github.com/monedula-dev/monedula-acl-rbac-converter)。如果你发现了 bug 或有改进建议，欢迎提交 issue。