Monedula
monedula-acl-rbac-converter docs menu

Plan and review role bindings

Turn acls.json into plan.json and report.txt, review mapped, unmapped and rejected ACLs, and edit the plan safely before applying it.

How-to guides 4 of 11

3 min read

Updated 5 October 2026

Markdown

On this page

plan turns the ACL snapshot from extract into the role bindings to create. It writes plan.json, which every later step reads, and report.txt, which shows what each ACL became and why; reading the report is the main review point of a migration, before anything changes.

Before you start

Steps

1. Run plan

monedula-acl-rbac plan \
  --acls runs/2026-05-21T10-00-00Z/acls.json \
  --rules rules.yaml \
  --principals principals.yaml \
  --scopes scopes.yaml \
  --out runs/2026-05-21T10-00-00Z/plan.json

plan writes three files into the run directory: plan.json, its checksum plan.json.sha256, and report.txt. It prints a one-line summary to stderr, such as plan: 1 binding(s), 0 unmapped, 0 rejected, 0 warning(s). When the input has DENY ACLs, the line also counts the results of the DENY analysis.

2. Read report.txt

The report has one section per list of the plan, and two more:

  • Bindings: the role bindings to create, marked [CREATE], or [SKIP_EXISTS] when an existing binding already covers them. Each lists its role, principal, cluster scope, resource patterns and the source_acl_ids of the ACLs it replaces.
  • Unmapped: ACLs the rules could not translate, with a reason: NO_RULE_MATCH, HOST_RESTRICTED or CONFLICTING_EXISTING_BINDING.
  • Rejected: ACLs the tool will not convert. DENY ACLs are rejected with DENY_PERMISSION.
  • DENY analysis: for each DENY ACL, SAFE_TO_REMOVE, WOULD_GRANT_ACCESS or UNKNOWN; Remove DENY ACLs explains the classes.
  • Warnings: things to check, such as PARTIAL_RULE_COVERAGE, when the chosen roles do not grant every operation of the source ACLs, or MTLS_DN_PASS_THROUGH for a principal that looks like a TLS distinguished name and is passed through unmapped.

This is a binding from the text-dump example’s report, which also shows a rejected DENY:

  [CREATE] DeveloperRead for User:svc-analytics -> kafka=lkc-demo-1 on:
    - Topic:events. (PREFIXED)
    source_acl_ids: [11 12]

How ACLs map to RBAC roles explains why an ACL ends up in each list.

3. Resolve unmapped and rejected ACLs

plan exits 3 when the plan has any unmapped or rejected ACL. It still writes plan.json and report.txt, so you can read them. Then either fix the input and plan again, or accept the result:

  • Add a rule to rules.yaml for operations the defaults do not cover, or map principals in principals.yaml, and run plan again.

  • Accept ACLs that stay unconverted, for example DENY ACLs, which never convert:

    monedula-acl-rbac plan ... --allow-unmapped --allow-rejected

The two flags do not convert anything. They let plan exit 0 with those ACLs recorded as unmapped or rejected, and the ACLs stay in place on the cluster: delete-acls only deletes ACLs that a verified binding replaces.

4. Share the report

To view the report of a run again, or in another format, use report:

monedula-acl-rbac report --plan runs/2026-05-21T10-00-00Z/plan.json --format markdown

--format takes text, markdown or json (report.v1.json), and --out writes to a file instead of stdout. report exits 0 even when the plan has unmapped or rejected ACLs; add --strict to make it exit 3 instead, for example as a gate in a CI job.

5. Edit the plan before applying, if you need to

You can edit plan.json by hand, for example to drop a binding you are not ready to apply or to fix a principal. apply then refuses the plan with exit code 5, because its checksum no longer matches. After editing, re-validate the plan to refresh the checksum:

monedula-acl-rbac plan --revalidate runs/2026-05-21T10-00-00Z/plan.json

--revalidate checks the structure of the edited file, its schema version and the fields of every binding, and rewrites plan.json.sha256.

Check it worked

The plan line of monedula-acl-rbac status runs/2026-05-21T10-00-00Z shows the number of bindings, unmapped and rejected ACLs, and checksum_ok=true once the checksum matches the file.