skip to content

Walk through how the authorizer combines super.users, DENY/ALLOW ACLs, and the no-ACL fallback to reach a decision.

level: seniorimportance: must knowfreq 55%

answer

  1. super → deny → allow → fallback
  2. deny-wins, even over allow
  3. super user beats DENY (checked first)
  4. fallback only when zero ACLs match resource
  5. no matching ALLOW = denied (with default-deny)

basics

~10 s

Order: super user → ALLOWED. Else any matching DENY → DENIED. Else any matching ALLOW → ALLOWED. Else fall back to allow.everyone.if.no.acl.found (true=allow, false=deny). DENY always beats ALLOW.

solid answer

~50 s

The authorizer reaches a single ALLOWED/DENIED decision per Action using a fixed precedence. First, if the principal is in super.users, it's ALLOWED immediately — no ACL evaluation. Otherwise it gathers ACLs matching the resource and operation and applies deny-wins: if any matching DENY ACL exists, the result is DENIED, even if ALLOW ACLs also match. If no DENY but at least one matching ALLOW exists, it's ALLOWED. If no ACL matches the resource at all, it falls back to allow.everyone.if.no.acl.found — true means ALLOWED, false (the secure default) means DENIED. Practical consequences: you cannot grant your way around a DENY; a single ALLOW ACL on a resource removes the no-ACL fallback for that resource; and super users are unconditionally allowed and unaffected by DENY ACLs. This deny-wins-then-default-deny model is why least-privilege ACL design works cleanly in Kafka.

go deeper

for a junior

Recall the order: super user, then deny, then allow, then the no-ACL fallback; deny beats allow.

for a middle

Explain that the fallback only fires with zero matching ACLs and that one ALLOW locks a resource.

for a senior

Reason through mixed ALLOW/DENY, host scoping, prefixed patterns, and the super-user-beats-deny rule.

for a principal

Design least-privilege ACL schemes using broad ALLOW + targeted DENY carve-outs, and explain why super users can't be DENY-restricted.

## The goal For each `Action` (an operation like READ/WRITE/CREATE on a specific resource such as a topic, group, or cluster), the authorizer must answer **ALLOWED** or **DENIED**. It does so with a strict precedence. ## The precedence (highest to lowest) 1. **Super user check.** If the request's `KafkaPrincipal` is in `super.users`, return **ALLOWED** immediately. No ACLs are consulted. Super users are not even subject to DENY ACLs. 2. **Matching DENY ACL (deny-wins).** Collect ACLs whose resource pattern (literal or prefixed), operation, principal, and host match. If **any** matched ACL is a **DENY**, return **DENIED** — this beats any ALLOW. 3. **Matching ALLOW ACL.** If no DENY matched but at least one **ALLOW** matches, return **ALLOWED**. 4. **No-ACL fallback.** If **no** ACL matched this resource at all, defer to `allow.everyone.if.no.acl.found`: `true` → ALLOWED, `false` (default) → DENIED. ## Why deny-wins matters Because DENY is evaluated before ALLOW, you can grant a group broad access and then carve out exceptions with targeted DENY ACLs, confident the DENY cannot be overridden by a broader ALLOW. There's no 'most specific rule wins' nuance — any matching DENY is decisive. ## The fallback subtlety (restated) Step 4 only triggers when **zero** ACLs match the resource. As soon as a resource has any ACL, it's governed by steps 2–3 and the fallback is irrelevant for it. With `allow.everyone.if.no.acl.found=true`, adding one ALLOW ACL therefore *locks down* a resource to just the named principals. ## Super users vs DENY A frequently missed point: **a DENY ACL cannot stop a super user.** Super user status is checked first and short-circuits everything. If you need to restrict an account, it must not be a super user — you can't 'DENY' a super user. ## Worked examples - Principal `User:admin` is in super.users → produce on any topic: **ALLOWED** (step 1), even if a DENY exists. - `User:app` has ALLOW READ on topic `t` and DENY READ on `t` → **DENIED** (step 2, deny-wins). - `User:app` has ALLOW WRITE on `t`, requests READ on `t` → no DENY, no matching ALLOW for READ, but the resource *has* ACLs, so step 4's fallback does **not** apply for the resource… actually the operation READ has no matching ALLOW and no DENY: since at least the resource has ACLs but none match this operation, result is DENIED (no matching ALLOW). The fallback only saves you when there are literally no ACLs for the resource. - `User:app` requests on topic `z` with no ACLs anywhere for `z`, fallback=false → **DENIED**; fallback=true → ALLOWED. ## Edge cases - Host-specific ACLs: matching also considers the client host; a DENY for a host applies only from that host. - Prefixed ACLs (resource pattern type PREFIXED) and literal ACLs can both match; deny-wins still applies across all matches. - Anonymous principal (`User:ANONYMOUS`) is subject to the same rules unless it's a super user.

  • Can you stop a super user from doing something with a DENY ACL?
    No. The super.users check is first and short-circuits to ALLOWED before any ACL — including DENY — is evaluated. To restrict the account, remove it from super.users and govern it with ACLs instead.
  • A principal has ALLOW WRITE on a topic and requests READ. allow.everyone.if.no.acl.found=true. Allowed or denied?
    Denied. The resource has ACLs, so the no-ACL fallback doesn't apply. There's no matching ALLOW for READ and no DENY, so the result is DENIED for lack of an authorizing ALLOW.

saying these in an interview costs you the question

  • Saying ALLOW can override DENY — deny always wins.
  • Claiming a DENY ACL can restrict a super user.
  • Thinking the no-ACL fallback applies when a resource has ACLs but none match the operation (it only applies when zero ACLs match the resource).
  • Assuming 'most specific rule wins' — Kafka has no specificity tie-break; any DENY is decisive.

context