Monedula

monedula-acl-rbac-converter v0.10.0, AGPL-3.0

Migrate Kafka ACLs to RBAC and verify access

monedula-acl-rbac-converter reads your Kafka ACLs from wherever they live, plans the equivalent Confluent RBAC role bindings, applies them, and asks MDS whether every original permission still holds. Only then does it write the script that deletes the old ACLs.

Go
go install github.com/monedula-dev/monedula-acl-rbac-converter/cmd/monedula-acl-rbac@latest
runs/<timestamp>/plan.json (excerpt)
{
  "schema_version": "1",
  "bindings": [
    {
      "id": "rb-b6fac2ae9aa0",
      "action": "CREATE",
      "principal": "User:svc-analytics",
      "role": "DeveloperRead",
      "scope": { "kafka_cluster": "lkc-demo-1" },
      "resource_patterns": [
        { "resource_type": "Topic", "name": "events.", "pattern_type": "PREFIXED" }
      ],
      "source_acl_ids": [11, 12]
    }
  ]
}
terminal
RUN=runs/2026-05-21T10-00-00Zmonedula-acl-rbac extract --from text --input acls.txt --out $RUN/acls.jsonmonedula-acl-rbac plan --acls $RUN/acls.json --rules rules.yaml --principals principals.yaml --scopes scopes.yaml --out $RUN/plan.jsonmonedula-acl-rbac auth login --mds-url https://mds.example.commonedula-acl-rbac apply --plan $RUN/plan.json --mds-url https://mds.example.com --confirmmonedula-acl-rbac verify --plan $RUN/plan.json --mds-url https://mds.example.com# exit 0: every source ACL is still allowed; exit 5: some access is missing or unknown

plan.json excerpt from examples/text-dump/expected/ in the repository.

The problem

ACLs and RBAC do not map one-to-one.

Moving an existing cluster to Confluent RBAC means turning every ACL into a role binding. Some ACLs, such as DENY rules, should not be converted at all, others match no mapping rule, and a binding can apply cleanly and still grant nothing. Done by hand, each of these fails silently.

9
ACL sources, from a live cluster to Strimzi and CFK manifests
3
ways to hand bindings on: shell script, CFK manifest, MDS curl
~10k
ACLs per run, held in memory

How it works

  1. 01

    Extract extract

    Read ACLs from any of nine sources into a canonical acls.json.

  2. 02

    Plan plan

    Map them to role bindings with default rules you can override; read report.txt.

  3. 03

    Apply apply

    Create the bindings in MDS. Nothing changes without --confirm.

  4. 04

    Verify verify

    Ask MDS whether each original permission is still allowed.

  5. 05

    Retire delete-acls

    Generate the deletion script, with its rollback, and run it yourself.

  1. Source ACLs live cluster; kafka-acls dump; JSON, YAML, CSV; Strimzi; CFK; Kubernetes
  2. plan.json every ACL mapped, unmapped or rejected; checksummed
  3. Path A: apply to MDS, then verify effective access
    Path B: emit script, CFK manifest, MDS curl for your pipeline
  4. Retire ACLs a deletion script you inspect and run
The source ACLs become one checksummed plan, which is applied to MDS or emitted for your pipeline before the old ACLs are retired.

Effective access, verified

verify asks MDS, for every source ACL, whether the original principal, operation and resource is actually allowed now, not just whether a binding row exists. A mismatched cluster ID produces bindings that apply cleanly and grant nothing; this is the check that catches it.

terminal
monedula-acl-rbac verify \
  --plan runs/2026-05-21T10-00-00Z/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token

Every ACL lands in one of three lists

Scope is never widened: a prefixed ACL on Topic:foo* becomes a binding on Topic:foo*, never a cluster-wide grant. Plans are checksummed, and a stale or edited plan is refused until you revalidate it.

bindings
role bindings to create, each listing the source ACL ids it replaces
unmapped
ACLs no rule could translate; you decide what to do with them
rejected
ACLs the tool will not convert, such as DENY rules

With MDS access, or without it

Give the tool MDS access and it applies and verifies the bindings itself. Or keep MDS credentials where they are: emit the plan as a Confluent CLI script, CFK ConfluentRolebinding manifests or MDS curl commands, and let your pipeline apply them, then run verify later from a host that has MDS access. For a quick look, convert runs extract, plan and emit in one call.

Choosing a path

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

A run directory you can show an auditor

Every run keeps the input snapshot, the effective rules, the plan, the logs and the rollback scripts in one directory, with a record of which credentials source was used. Two apply runs cannot race on the same directory.

runs/2026-05-21T10-00-00Z/
  acls.json          source ACL snapshot
  plan.json          checksummed plan
  report.txt         what maps to what, and why
  would-apply.log    dry-run calls
  apply.log          what was created
  verify.json        effective-access results
  delete-acls.sh     generated, run by you

Install

Go
go install github.com/monedula-dev/monedula-acl-rbac-converter/cmd/monedula-acl-rbac@latest

Release archives for Linux, macOS and Windows, with a cosign-signed checksums file and an SBOM, are on the releases page. See install and verify a release.

Questions

Is monedula-acl-rbac-converter free, and can I use it at work?
Yes. It is AGPL-3.0 with no paid edition, and running it on your own infrastructure does not oblige you to share your code or configuration: AGPL obligations apply when you distribute it, modified or not, or let others use a modified version over a network.
Will it delete my ACLs?
Not by itself: apply never deletes source ACLs, and delete-acls writes a kafka-acls --remove script, with its rollback, for you to inspect and run. The script covers only ACLs that passed verify; if none passed, delete-acls stops with an error. See delete the converted ACLs.
What happens to DENY ACLs?
They are never converted automatically; the plan lists them as rejected. delete-deny-acls generates a script that re-checks effective permissions for each ACL when it runs, and wildcard-principal DENYs are never removable by the tool. See remove DENY ACLs.
How many ACLs can it handle?
Up to about 10,000 ACLs per run, held in memory. For more, partition by principal, one run directory per batch.

Support

Help from the people who build it

We can help you run monedula-acl-rbac-converter across a large estate, from design to day-to-day operations.

Part of
Monedula Flock

More free tools for Apache Kafka from the same team. About Flock

Go, AGPL-3.0, v1.0.0

monedula-gitops

GitOps for Apache Kafka: topics, access, quotas, schemas, SCRAM users and Confluent RBAC, from a CLI or a Kubernetes operator.

Go, Apache-2.0, v0.11.0

monedula-sim-link

A read-only Go CLI that turns a real Kafka cluster into a shareable Kafka Simulator link, with an MCP server for AI agents.

Free, runs in your browser

Kafka Simulator

An interactive, deterministic Apache Kafka simulator in the browser: break a cluster, scrub the timeline and read why it reacted.