Monedula
monedula-acl-rbac-converter docs menu

Remove DENY ACLs

Remove DENY ACLs with delete-deny-acls, whose script re-checks effective permissions per ACL at run time. Wildcard DENYs stay.

How-to guides 8 of 11

4 min read

Updated 5 October 2026

Markdown

On this page

delete-acls never touches DENY ACLs. delete-deny-acls removes the ones you no longer need through a script that you run, which checks each DENY against MDS again at that moment and removes it only if that would not grant access.

Before you start

  • A plan made with --allow-rejected, which lists the DENY ACLs as rejected. See Plan and review role bindings.
  • A verify.json for the current plan, with every result EFFECTIVE_OK, at its default place in the run directory, where the script reads it again. delete-deny-acls refuses while any result is missing or unknown.
  • MDS credentials as a token file, or a user name and a password file. A token cached by auth login is not enough: the script may run hours later, and it has to authenticate without you.
  • The bootstrap servers and a Kafka client properties file for a principal that may delete ACLs.
  • A host with the run directory, monedula-acl-rbac and kafka-acls on the PATH, to run the script. If your Kafka tool has another name or location, such as kafka-acls.sh, set MONEDULA_KAFKA_ACLS_BIN to it.

Steps

1. Check the DENY analysis

Read the DENY analysis section of report.txt. plan classifies every DENY ACL:

  • SAFE_TO_REMOVE: no Allow ACL in the input grants the same principal the same operation on that resource.
  • WOULD_GRANT_ACCESS: an Allow ACL does, so removing the DENY would open access.
  • UNKNOWN: the analysis cannot tell, as for every wildcard principal.

Only SAFE_TO_REMOVE DENY ACLs can be removed by this tool.

2. Generate the script

monedula-acl-rbac delete-deny-acls \
  --plan runs/2026-05-21T10-00-00Z/plan.json \
  --verify runs/2026-05-21T10-00-00Z/verify.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --bootstrap-server kafka.example.com:9093 \
  --command-config admin.properties \
  --principal User:alice \
  --confirm \
  --i-understand-this-may-grant-access

--principal, or --principal-file, is required: there is no untargeted sweep. Both --confirm and --i-understand-this-may-grant-access are required too; --i-understand-this-is-destructive is not accepted on this command.

delete-deny-acls writes four files into the run directory:

  • delete-deny-acls.sh: the deletion script.
  • deleted-deny-acls.json: the DENY ACLs that the script may remove.
  • rollback-deny.sh: a script that recreates them.
  • runtime.env: the Kafka and MDS connection settings, the credential references and a per-run token, with mode 0600. Secrets are never written into the script or onto command lines.

3. Read the script

The script contains no bare kafka-acls --remove calls. It checks that runtime.env exists with mode 0600, loads it, and then runs one line per DENY:

monedula-acl-rbac delete-deny-one --run-dir <absolute run directory> --acl-id <id>

delete-deny-one is an internal helper of this script, not a command you run yourself. For its ACL, it checks the plan and verify.json again, asks MDS whether the principal now holds any grant that overlaps the denied operation and resource, and removes the DENY only if none does. Because the check happens at run time, you can inspect, reorder or partly run the script by hand, even if access changed since you generated it.

4. Run the script

bash runs/2026-05-21T10-00-00Z/delete-deny-acls.sh

Like the delete-acls script, it refuses to run, with exit code 5, when plan.json changed or cannot be hashed. Each DENY gets one line in delete-deny.log:

  • OK: the live check found the DENY safe to remove, and it was removed.
  • SKIP with WOULD_GRANT_ACCESS: something now grants the denied access, for example a binding added after you planned, so the DENY stays. There is no override.
  • SKIP with EFFECTIVE_UNKNOWN: the live check failed, so the DENY stays.
  • FAIL: the removal itself failed, and the script stops.

If MDS rejects the credentials, for example because the token expired, the script stops at that ACL instead of skipping the rest.

The script deletes runtime.env when it exits, so the per-run token does not outlive the run. To run it again, generate it again with delete-deny-acls.

Wildcard DENYs stay

DENY ACLs for a wildcard principal, such as User:*, a bare * or any <Type>:*, are never removable by this tool. They cover principals the analysis cannot enumerate, so plan classifies them UNKNOWN, delete-deny-acls will not include them and there is no override. If you are certain that one must go, remove it by hand with kafka-acls.

Check it worked

delete-deny.log has an OK line for each DENY that was removed and a SKIP line, with the reason, for each one that stayed. kafka-acls --list no longer shows the removed DENY ACLs. To restore them, run rollback-deny.sh against the same cluster.