Give each Kafka service its own principal, then grant it only the operations it needs on only the topics and consumer groups it touches. The kafka-acls.sh tool has producer and consumer shortcuts that bundle the right operations, and prefixed patterns let you cover a naming family without a wildcard.
Start with one principal per service
Kafka ACLs read as a sentence: a principal is allowed or denied an operation from a host on a resource that matches a pattern. If five services share one principal, you cannot tell them apart in an ACL, and you cannot revoke one without breaking four.
So the first step is identity. Whether the principal comes from a TLS certificate or a SASL login, create one per service, and name it after the service rather than the team.
Use the producer and consumer shortcuts
The ACL tool accepts a producer option and a consumer option so you do not have to remember which low-level operations each role needs. A producer grant on a topic looks like this:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:Bob --producer --topic Test-topic
A consumer needs a topic and a consumer group, so the command takes both:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:Alice --consumer --topic Test-topic --group Group-1
Those two examples come from the Kafka documentation. Note that the consumer grant names a group. A consumer without group access cannot commit offsets, so forgetting it shows up as a failure at runtime, not as a quiet gap.
Prefer prefixed patterns to wildcards
A wildcard topic grant is the quickest way to make an ACL meaningless. If a team's topics all start with the same string, a prefixed resource pattern grants access to that family only:
bin/kafka-acls.sh --bootstrap-server localhost:9092 --add --allow-principal User:Jane --producer --topic Test- --resource-pattern-type prefixed
This only works if your topic naming is consistent. That is a good reason to agree on a convention before you write ACLs, not after.
Lock the host list only if you can keep it true
ACLs accept host restrictions, but the documentation says allow-host and deny-host support IP addresses only, not hostnames. In autoscaled or containerised environments, addresses churn. A stale host list breaks working services, and teams respond by widening it to everything. Use host restrictions where addresses are stable and rely on the principal everywhere else.
Audit what actually applies to a topic
Listing ACLs on a topic returns only those attached to that exact pattern. Other ACLs, such as ones on a wildcard or a prefix, can also affect access. The docs describe a match pattern type for listing every ACL that touches a given topic. Run that before you declare a topic locked down.
Keep deny rules for the rare case
By default, a principal with no allow ACL is denied. The documentation says explicit deny options are for rare cases where a broad allow exists and one principal must be carved out. If you find yourself writing many deny rules, the broad allow is the problem.
For a related setting that quietly undoes all of this, see Kafka allow.everyone.if.no.acl.found: when it is safe.
If you want to find out which client libraries and versions your services pull in, Safeguard's SBOM and dependency scanning covers that, and there is a free scan at gold.safeguard.sh/scan.
Quick check
Why does a Kafka consumer ACL include a group?
Consumers read through a consumer group and commit offsets to it. The consumer shortcut in the ACL tool takes a topic and a group so that both permissions are granted together.
Is a wildcard topic grant ever fine?
For a single trusted admin tool, maybe. For application services, a prefixed pattern gives you the same convenience with a smaller blast radius.
Sources
Last reviewed: 19 October 2026.