Moving ZooKeeper ACLs and SCRAM credentials to KRaft

Your ZooKeeper-era Kafka security has to land in the KRaft metadata log without gaps, so clients keep working and no resource ends up open or locked out. This page shows what maps, what does not, and how to test each phase.

On this page

Why ACLs and SCRAM credentials need their own migration plan

A ZooKeeper-based cluster that uses AclAuthorizer and SCRAM users has to move its security state to KRaft as a deliberate workstream of its own, because the access rules and credentials do not follow the data or the clients automatically. Kafka 4.0 supports only KRaft mode and removed ZooKeeper mode, so according to the Kafka upgrade notes, a ZooKeeper-based cluster must finish migrating to KRaft before it can move to any 4.x release. Security is therefore on the critical path, not an afterthought at the end of the broker move.

Treat the security state as its own stream with its own owner, inventory and test plan. Moving partitions, switching producers and consumers, and replacing controllers each change how the cluster behaves, but none of them proves that every principal still has the same permissions. Effort depends mainly on how many principals, ACL bindings and client applications the cluster serves, and on how many of those clients are owned by teams you must coordinate with. Confirm those counts before you agree on a schedule, because a partner quote should follow from them.

Start by exporting the current ACLs and SCRAM user list and confirming who owns each principal. In a KRaft cluster the StandardAuthorizer keeps ACLs in the metadata log, and resources without a matching ACL are limited to super users unless allow.everyone.if.no.acl.found is set to true. That default means a missed ACL can cause an outage rather than a silent gap, so each phase needs a documented access test against the expected principals. The Kafka authorization documentation describes the StandardAuthorizer behavior you will verify against.

Which ZooKeeper security settings map to KRaft and which do not

This table compares each ZooKeeper-era security element with its KRaft counterpart and marks what carries over, what changes location and what is removed. Read the rows as a checklist: anything marked as moved or removed needs a replacement control, a configuration change or a test before the cluster leaves migration mode. The main takeaway is that ACLs and SCRAM credentials move into the metadata log, while encryption of that data is no longer provided by Kafka.

ElementZooKeeper-era setting or storeKRaft equivalent and what to check
Authorizer classkafka.security.authorizer.AclAuthorizer reading ACLs from ZooKeeperStandardAuthorizer, which stores ACLs in the cluster metadata log. Confirm the class name in your broker configuration before the switch.
Where ACLs liveZooKeeper znodes written by the AclAuthorizerCluster metadata log. Export and review existing ACLs first, then recreate or verify them after the controllers are running.
Default for resources without ACLsGoverned by the ZooKeeper-based authorizer's own configurationResources with no ACL are restricted to super users unless allow.everyone.if.no.acl.found is set to true. Decide this value deliberately and test it.
SCRAM credentialsStored in ZooKeeperStored in the metadata log. Credentials can be created at format time with kafka-storage.sh or afterward with kafka-configs.sh. Re-create or verify each user.
ZooKeeper password encoderPassword encoder settings protect sensitive values written to ZooKeeperRemoved in KRaft mode. Sensitive data is stored in metadata records without encryption, so encryption at rest must come from the platform (disk, volume or storage layer).
Super userssuper.users configurationStill required for administrative access after the switch. Confirm the principal names match the identities your clients use.
Client authentication mechanismsSASL mechanisms and TLS listenersListener and SASL settings carry over, but SCRAM users must exist in the metadata log before clients reconnect. Test each listener.
Authorizer plug-in modelPluggable authorizerAuthorization remains pluggable and can integrate with external services. Confirm any custom authorizer supports KRaft before relying on it.

Which documented paths move ACLs and credentials

The documented route for authorization rules on a KRaft cluster is to recreate them. Once the cluster runs with the StandardAuthorizer, ACLs live in the cluster metadata log, so you define them again with the admin tooling and confirm each one matches the ZooKeeper-era rule. Start by exporting the current ACL list from the source cluster so you have a written reference for every principal, resource type, pattern type and operation in use.

  • Inventory before writing: List every ACL on the source cluster, including prefixed and literal resource patterns, and mark which ones belong to service accounts that are being retired.
  • Recreate with the admin tool: Use kafka-acls.sh against the KRaft controllers to add each rule, grouped by application so failures are easy to trace.
  • Account for super users: Under the StandardAuthorizer, resources without ACLs are restricted to super users unless allow.everyone.if.no.acl.found is set to true, so an omitted rule can block a client rather than fail open.
  • Diff the result: Compare the KRaft ACL list with your inventory and record every difference, including rules you intentionally dropped.
  • Test per principal: Confirm that each application can still produce or consume on the resources it needs and is refused on the ones it should not reach.

Confirm the exact flags and behavior for your Kafka version in the authorization documentation before you script anything.

How to sequence the security cutover around the migration phases

This sequence moves ACLs and SCRAM credentials out of ZooKeeper and into the KRaft metadata log without a window where clients lose access. Each phase ends with an access test matrix, and ZooKeeper settings are removed only after those tests pass.

  1. Inventory principals, ACLs and listeners

    Before touching the cluster, export every ACL, every SCRAM user and every listener with its security protocol, and map each to the client group that depends on it: producers, consumers, Kafka Connect workers, Streams applications, admin tools and inter-broker traffic. Record which principals are used by which applications and who owns each one. The step is done when the team has a single inventory document that the access test matrices in later steps can reference. Confirm with your Kafka administrators which ACLs exist on the live cluster, since ACLs added by hand are easy to miss in older runbooks.

  2. Build the KRaft authorizer and SCRAM users in a test cluster

    In a separate KRaft test cluster, configure the StandardAuthorizer and recreate the same ACLs from the inventory. Create the SCRAM users with kafka-configs.sh, or with kafka-storage.sh at format time if you bootstrap credentials that way. In KRaft, the StandardAuthorizer stores ACLs in the cluster metadata log, and resources without ACLs are limited to super users unless allow.everyone.if.no.acl.found is set to true, so confirm that setting explicitly for your environment. The step closes when every principal in the inventory authenticates and passes its test matrix, and each denied action is confirmed to be intentionally denied.

  3. Test access from each client group before dual running

    Run a matrix that records, for each client group, the authentication mechanism, the topics and groups it touches, the operations it performs (read, write, describe, create, alter) and the expected result. Include negative cases such as a consumer attempting to produce and a Connect worker reading a topic outside its prefix. Repeat the matrix after every change to the authorizer configuration. The output is a signed-off matrix that the platform owner and each application owner have reviewed, which becomes the baseline for the production phases.

  4. Run the dual-running phase with matching security configuration

    During dual running, the ZooKeeper-based cluster stays live while controllers are brought up in migration mode. Keep the existing ZooKeeper authorizer and credentials in place so clients continue to work, and verify that the KRaft-side ACLs and SCRAM users written during the test cluster work are in sync with the ZooKeeper data for every principal in the inventory. Rerun the access matrix from each client group against the migrating cluster. The step closes when the matrix passes with no unexpected denials and the team has confirmed that no client depends on an ACL that exists only on one side.

  5. Migrate to KRaft with controllers in place

    Move brokers to KRaft mode in the sequence described in the migration documentation, with the KRaft controllers running and the cluster in migration mode. Rerun the full access matrix after each broker role change, not only at the end, so a failure can be traced to a specific change. Check that the authorizer, the SCRAM credentials and the listener security settings are reading from the KRaft metadata and that clients reconnect with the same principals. Finalize only after the matrix passes on every phase and the team has reviewed the revert options in the sibling rollback topic, because finalization is one-way.

  6. Remove ZooKeeper settings and authorizer config

    Only after the access matrix passes on the finalized KRaft cluster, remove the ZooKeeper connection settings, the ZooKeeper password encoder settings and the AclAuthorizer configuration from broker and controller configuration files. Keep a copy of the previous configuration in version control so the change can be reviewed. Note that in KRaft mode Kafka stores sensitive data in metadata records without encrypting it, so the team should confirm how credential material is protected at the storage and access layers. The step is done when the cluster starts cleanly with the reduced configuration and the final access matrix passes again.

  7. Record evidence and schedule access reviews

    Archive the final access matrix, the configuration diff, the list of SCRAM users and the ACL export from the KRaft cluster. Assign an owner for each principal and set a recurring review of ACLs and SCRAM users against the inventory from the first step. Confirm which review cadence your own policies require, since this page does not set one. The step closes when the evidence bundle is stored where the security and compliance teams can retrieve it and each principal has a named owner.

What drives the effort of moving Kafka security to KRaft

This table lists the inputs that set how much work a ZooKeeper to KRaft security move takes and whether each one is a one-time task or an ongoing operation. Use it to size your own inventory before asking for a quote. The main takeaway is that ACL and credential volume drive the migration itself, while listener layout and environment count drive the testing that follows.

DriverWhy it changes effortOne-time or recurringHow to keep it down
ACL rules and resource patternsEach ACL must be exported, mapped to the StandardAuthorizer model and verified, including prefixed and literal patterns.One-time migration work, then recurring review of new grantsConsolidate rules into prefixed patterns and remove stale principals before the move
SCRAM principals and provisioning methodCredentials must be recreated in the metadata log with kafka-storage.sh or kafka-configs.sh, so each user needs a deliberate re-creation step.One-time for existing users, recurring for every new user or rotationScript provisioning from one source of truth so the same command path runs in every environment
Client applications and their auth configsEvery application's SASL mechanism, JAAS settings and credentials must be checked against the new cluster before cutover.One-time per application, recurring when clients change mechanismsInventory clients by mechanism and owner, and group them into batches for cutover
Custom authorizers or external authorization servicesPluggable or external authorizers add code and integration points that must be re-validated against the KRaft authorizer behavior.One-time redesign or retest, then recurring maintenance of the pluginConfirm whether the plugin can be retired in favor of ACLs in the metadata log before building work
Listener layout with mixed secured and unsecured pathsClusters that run unsecured or mixed listeners need each path classified and tested separately, since security is optional in Kafka.One-time classification and test design, recurring when listeners are addedRemove unsecured listeners where possible and document each remaining path with its owner
Number of environments to testEach environment (development, test, staging, production) needs its own access tests after each migration phase.One-time per environment for the migration, recurring for regression tests on upgradesAutomate access tests so the same suite runs in every environment after each phase
Allow.everyone.if.no.acl.found settingIf this setting is enabled, resources without ACLs stay open, which hides gaps in the migrated ACL set during testing.One-time review before cutover, then recurring audit of the settingKeep the default restrictive behavior and confirm every resource has an explicit ACL before cutover

What usually breaks access after a KRaft move

Access problems after a ZooKeeper to KRaft move rarely come from one bad setting. They come from gaps between where ACLs and credentials used to live, where they live now, and what clients still expect. Each card below names one failure pattern, why it hits this migration, and the prevention step to put in the plan before cutover.

Resources left without ACLs

In KRaft clusters the StandardAuthorizer stores ACLs in the metadata log, and any resource without an ACL is limited to super users. Topics, consumer groups and transactional IDs that existed in ZooKeeper-era ACLs may not have been carried over one for one. Before cutover, export the current ACL list, map each principal to each resource type, and confirm that every production client still has an explicit grant on the resources it uses.

Open fallback set by mistake

The allow.everyone.if.no.acl.found setting, when set to true, lets any principal access resources that have no ACL. Teams often turn it on during migration to stop failures quickly, then leave it in place. Treat it as a temporary diagnostic setting, record who changed it and when, and confirm in a review that it is false or removed before the cluster takes production traffic.

SCRAM credentials not re-created

SCRAM credentials are stored in the metadata log, so they are not carried over automatically from the old ZooKeeper store in the way many teams assume. Create each user's credential with kafka-storage.sh at format time or with kafka-configs.sh after the cluster is up. Keep the source of each password in your secrets manager, and check that every SCRAM user can authenticate on the new cluster before the old brokers are retired.

Secrets stored without encryption

In KRaft mode the ZooKeeper password encoder settings are removed, and sensitive data in metadata records is stored without Kafka encrypting it. Any SCRAM credential or other sensitive value that was protected under the old encoder now depends on the protection of the metadata log directories and their backups. Ask your security team to confirm disk encryption, file permissions, and backup encryption for every controller and broker log directory.

Clients keeping ZooKeeper-era settings

Client configurations, scripts and tooling sometimes still point at ZooKeeper addresses or use options that belonged to the old mode. Those clients fail or connect in unexpected ways once the ZooKeeper settings are removed from the brokers. Inventory every admin script, deployment template and application config that references ZooKeeper, switch them to bootstrap servers and current options, and test each one against a staging cluster in KRaft mode.

Tests that only cover producers

Smoke tests that publish and read a single topic can pass while consumers fail. Consumer groups have their own ACL resource and offset access, so a consumer may be denied even when producers work. Build the test plan to cover produce, consume, consumer group join and offset commit for each principal, plus SCRAM login for every user, and rerun it after each migration phase rather than once at the end.

Questions teams ask before moving Kafka security to KRaft

Can ZooKeeper ACLs and SCRAM users be copied to KRaft automatically?

Not as a single switch. ACLs must be re-expressed for the StandardAuthorizer, because in KRaft they are stored in the cluster metadata log rather than in ZooKeeper. SCRAM credentials also live in the metadata log and can be created with kafka-configs.sh or at format time with kafka-storage.sh. Your team should export the current ACL and SCRAM inventory from ZooKeeper, map each principal and resource, and then recreate them deliberately. Review each entry during the rebuild instead of trusting a bulk copy.

What drives the cost of moving Kafka security to KRaft?

Cost follows the number of principals, topics, consumer groups and client applications that depend on existing ACLs, plus how many authentication paths you run (SASL mechanisms, TLS listeners, and any external authorization service). Most of the effort is discovery: finding which clients use which credentials and which ACLs are no longer needed. Ask any provider for a written scope that separates the inventory, the ACL redesign, the testing per phase and the handover. Ongoing costs are limited to credential rotation and access reviews that your team runs after the migration.

How long does the security part of a KRaft migration usually take?

The duration depends on the size of your access model and how many teams must test their clients, not on a fixed rule. Plan time for the inventory, a review of default-deny behavior, a dry run in a non-production cluster, and a verification window after each migration phase. Kafka's upgrade notes state that clusters must move to KRaft before upgrading to 4.x, so that date often sets the deadline. Confirm the timeline against your own environment and your change calendar.

What must our internal team provide before the work starts?

Your team needs to provide a current list of clients, service accounts and their owners, a copy of the existing ACL definitions, and the SASL mechanisms each application uses. You also need access to the ZooKeeper ensemble for export, a staging cluster that mirrors production listeners, and a named approver for each application team. Without owners for each principal, nobody can confirm whether a missing ACL is a cleanup or an outage. Agree these inputs in the written scope before work begins.

Can our own engineers move Kafka security to KRaft without a partner?

Yes, if they have hands-on experience with Kafka authorization and SASL and enough time for a staged rollout. The steps are documented in the Kafka security and KRaft migration references, so an experienced team can plan the work internally. A partner adds value mainly when the access model is large, the change window is short, or no one on staff has run a KRaft migration before. Whichever path you choose, the decision should rest on a written plan and a tested rollback.

How do we test client access without causing an outage?

Test each phase against a representative set of clients before you move on. Confirm that each principal can still produce and consume on its expected topics, that consumer groups keep their offsets, and that unexpected principals are denied. Keep the StandardAuthorizer default behavior in mind: resources without an ACL are restricted to super users unless allow.everyone.if.no.acl.found is set to true, so a missing rule fails closed. Run denial tests as well as allow tests, and keep the ZooKeeper-based settings available until each phase passes.

Do we need to rotate SCRAM passwords as part of the move?

Rotation is not required by the migration itself, but it is a sensible checkpoint when credentials are recreated in a new store. Plan rotation as a separate, scheduled change so that a failed login can be traced to either the credential or the authorizer. Document which secrets your applications read, where they are stored and who can update them. Confirm your rotation policy with your security and compliance owners before the cutover.

Official Kafka documentation for this migration

The three Apache Kafka 4.3 pages below cover the security model, the credential store and the metadata differences that a ZooKeeper to KRaft move depends on. The upgrade notes set the Java and version prerequisites that must be met before the cluster can move to 4.x. Read them together before writing the cutover plan, because each one changes a different part of the security configuration.

Authorization and ACL model

This page explains how the StandardAuthorizer replaces AclAuthorizer in KRaft clusters and where ACLs live once they are migrated: in the cluster metadata log rather than in ZooKeeper. Check how the allow.everyone.if.no.acl.found setting behaves, because resources without an ACL are restricted to super users unless that setting is true. Compare every existing ACL against the new model before you switch authorizers, and test each principal's read, write and admin rights on a non-production cluster first.

SASL authentication and SCRAM

This page covers the documented SASL mechanisms, including SCRAM-SHA-256 and SCRAM-SHA-512, and how SCRAM credentials are stored in the metadata log. It also describes creating credentials with kafka-storage.sh at format time or with kafka-configs.sh on a running cluster. Confirm which users need credentials in the new cluster, since credentials created in ZooKeeper do not carry over automatically and must be recreated and tested for each client.

KRaft versus ZooKeeper differences

This page lists the configuration that changes between the two modes, including the removal of the ZooKeeper password encoder settings in KRaft mode. It also states that sensitive data in metadata records is stored without encryption, so the metadata log and its disks need the same protection you apply to ZooKeeper data. Use it as a checklist to remove obsolete ZooKeeper properties from broker configuration files and confirm that no broker still expects a ZooKeeper connection string.

Upgrade prerequisites and Java requirements

The upgrade notes state that ZooKeeper-based clusters must migrate to KRaft before upgrading to 4.x, and recommend that KRaft clusters older than 3.3.x first move to 3.9.x. Since Kafka 4.0, brokers, Kafka Connect and tools require Java 17, while clients and Kafka Streams applications require at least Java 11. Inventory every broker, Connect worker and client runtime against these numbers before scheduling the migration window, because a missing JVM upgrade can block a rolling restart.

How DeployOpen scopes and delivers the security cutover

DeployOpen fixes the scope of the security cutover in writing before any work starts. The written scope names the clusters involved, the authorizer change from AclAuthorizer to StandardAuthorizer, the SCRAM users to be recreated, and the access tests that define done. Quotes follow from that written scope, so the price reflects the number of principals, topics, consumer groups and applications that actually need to move, not an estimate made before anyone has looked at the cluster. Before the scope is signed, the team inventories every principal and ACL currently held in ZooKeeper, and records which of them are still in use. Unused service accounts and stale ACLs are often the largest source of avoidable rework, so the inventory is where the reader should expect the most decisions to be made.

Once the scope is agreed, the KRaft authorizer configuration, the SCRAM credentials and the ACL set are built and tested inside the client's own infrastructure, in a non-production cluster first. Each access test is run against the cluster in the phase it belongs to, so a failed test points to one change rather than to a whole migration. Passwords and SCRAM secrets are handled through the client's own secret store, because KRaft stores credential records in the metadata log without encrypting them, and the client's controls around that log should be confirmed before go-live. DeployOpen prepares the evidence for the client's assessment, such as ACL exports, test results and change records, but it does not issue audit reports, attestations or certifications. The client's independent auditor or certification body makes that determination. After cutover, a retainer can cover ongoing access reviews, credential rotation and upgrades if the client wants continued support, and that retainer is quoted separately from the migration scope.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.