diff --git a/src/storage.rs b/src/storage.rs
index a140b28ffc9b40f7dee20da0eef1d0898568c6c9..26491364837d38bd6f33deb956f4dd9197dc9ceb 100644
--- a/src/storage.rs
+++ b/src/storage.rs
@@ -2307,14 +2307,14 @@ impl SchemaDef for UserDef {
     #[inline(always)]
     fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_create_user_on_master(self)?;
+        acl::on_master_create_user(self)?;
         Ok(())
     }
 
     #[inline(always)]
     fn on_delete(user_id: &UserId, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_drop_user_on_master(*user_id)?;
+        acl::on_master_drop_user(*user_id)?;
         Ok(())
     }
 }
@@ -2335,14 +2335,14 @@ impl SchemaDef for RoleDef {
     #[inline(always)]
     fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_create_role_on_master(self)?;
+        acl::on_master_create_role(self)?;
         Ok(())
     }
 
     #[inline(always)]
     fn on_delete(user_id: &UserId, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_drop_role_on_master(*user_id)?;
+        acl::on_master_drop_role(*user_id)?;
         Ok(())
     }
 }
@@ -2363,236 +2363,244 @@ impl SchemaDef for PrivilegeDef {
     #[inline(always)]
     fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_grant_privilege_on_master(self)?;
+        acl::on_master_grant_privilege(self)?;
         Ok(())
     }
 
     #[inline(always)]
     fn on_delete(this: &Self, storage: &Clusterwide) -> traft::Result<()> {
         _ = storage;
-        acl_revoke_privilege_on_master(this)?;
+        acl::on_master_revoke_privilege(this)?;
         Ok(())
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// acl global
+// acl
 ////////////////////////////////////////////////////////////////////////////////
 
-/// Persist a user definition in the internal clusterwide storage.
-pub fn acl_global_create_user(storage: &Clusterwide, user_def: &UserDef) -> tarantool::Result<()> {
-    storage.users.insert(user_def)?;
-    Ok(())
-}
+pub mod acl {
+    use super::*;
 
-/// Remove a user definition and any entities owned by it from the internal
-/// clusterwide storage.
-pub fn acl_global_change_user_auth(
-    storage: &Clusterwide,
-    user_id: UserId,
-    auth: &AuthDef,
-) -> tarantool::Result<()> {
-    storage.users.update_auth(user_id, auth)?;
-    Ok(())
-}
+    ////////////////////////////////////////////////////////////////////////////
+    // acl in global storage
+    ////////////////////////////////////////////////////////////////////////////
 
-/// Remove a user definition and any entities owned by it from the internal
-/// clusterwide storage.
-pub fn acl_global_drop_user(storage: &Clusterwide, user_id: UserId) -> tarantool::Result<()> {
-    storage.privileges.delete_all_by_grantee_id(user_id)?;
-    storage.users.delete(user_id)?;
-    Ok(())
-}
+    /// Persist a user definition in the internal clusterwide storage.
+    pub fn global_create_user(storage: &Clusterwide, user_def: &UserDef) -> tarantool::Result<()> {
+        storage.users.insert(user_def)?;
+        Ok(())
+    }
 
-/// Persist a role definition in the internal clusterwide storage.
-pub fn acl_global_create_role(storage: &Clusterwide, role_def: &RoleDef) -> tarantool::Result<()> {
-    storage.roles.insert(role_def)?;
-    Ok(())
-}
+    /// Remove a user definition and any entities owned by it from the internal
+    /// clusterwide storage.
+    pub fn global_change_user_auth(
+        storage: &Clusterwide,
+        user_id: UserId,
+        auth: &AuthDef,
+    ) -> tarantool::Result<()> {
+        storage.users.update_auth(user_id, auth)?;
+        Ok(())
+    }
 
-/// Remove a role definition and any entities owned by it from the internal
-/// clusterwide storage.
-pub fn acl_global_drop_role(storage: &Clusterwide, role_id: UserId) -> Result<()> {
-    storage.privileges.delete_all_by_grantee_id(role_id)?;
-    if let Some(role_def) = storage.roles.by_id(role_id)? {
-        // Revoke the role from any grantees.
-        storage
-            .privileges
-            .delete_all_by_granted_role(&role_def.name)?;
-        storage.roles.delete(role_id)?;
+    /// Remove a user definition and any entities owned by it from the internal
+    /// clusterwide storage.
+    pub fn global_drop_user(storage: &Clusterwide, user_id: UserId) -> tarantool::Result<()> {
+        storage.privileges.delete_all_by_grantee_id(user_id)?;
+        storage.users.delete(user_id)?;
+        Ok(())
     }
-    Ok(())
-}
 
-/// Persist a privilege definition in the internal clusterwide storage.
-pub fn acl_global_grant_privilege(
-    storage: &Clusterwide,
-    priv_def: &PrivilegeDef,
-) -> tarantool::Result<()> {
-    storage.privileges.insert(priv_def)?;
-    Ok(())
-}
+    /// Persist a role definition in the internal clusterwide storage.
+    pub fn global_create_role(storage: &Clusterwide, role_def: &RoleDef) -> tarantool::Result<()> {
+        storage.roles.insert(role_def)?;
+        Ok(())
+    }
 
-/// Remove a privilege definition from the internal clusterwide storage.
-pub fn acl_global_revoke_privilege(
-    storage: &Clusterwide,
-    priv_def: &PrivilegeDef,
-) -> tarantool::Result<()> {
-    // FIXME: currently there's no way to revoke a default privilege
-    storage.privileges.delete(
-        priv_def.grantee_id,
-        &priv_def.object_type,
-        &priv_def.object_name,
-        &priv_def.privilege,
-    )?;
+    /// Remove a role definition and any entities owned by it from the internal
+    /// clusterwide storage.
+    pub fn global_drop_role(storage: &Clusterwide, role_id: UserId) -> Result<()> {
+        storage.privileges.delete_all_by_grantee_id(role_id)?;
+        if let Some(role_def) = storage.roles.by_id(role_id)? {
+            // Revoke the role from any grantees.
+            storage
+                .privileges
+                .delete_all_by_granted_role(&role_def.name)?;
+            storage.roles.delete(role_id)?;
+        }
+        Ok(())
+    }
 
-    Ok(())
-}
+    /// Persist a privilege definition in the internal clusterwide storage.
+    pub fn global_grant_privilege(
+        storage: &Clusterwide,
+        priv_def: &PrivilegeDef,
+    ) -> tarantool::Result<()> {
+        storage.privileges.insert(priv_def)?;
+        Ok(())
+    }
 
-////////////////////////////////////////////////////////////////////////////////
-// acl
-////////////////////////////////////////////////////////////////////////////////
+    /// Remove a privilege definition from the internal clusterwide storage.
+    pub fn global_revoke_privilege(
+        storage: &Clusterwide,
+        priv_def: &PrivilegeDef,
+    ) -> tarantool::Result<()> {
+        // FIXME: currently there's no way to revoke a default privilege
+        storage.privileges.delete(
+            priv_def.grantee_id,
+            &priv_def.object_type,
+            &priv_def.object_name,
+            &priv_def.privilege,
+        )?;
 
-/// Create a tarantool user. Grant it default privileges.
-pub fn acl_create_user_on_master(user_def: &UserDef) -> tarantool::Result<()> {
-    let sys_user = Space::from(SystemSpace::User);
+        Ok(())
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // acl in local storage on replicaset leader
+    ////////////////////////////////////////////////////////////////////////////
 
-    // This impelemtation was copied from box.schema.user.create excluding the
-    // password hashing.
-    let user_id = user_def.id;
-    let euid = ::tarantool::session::euid()?;
+    /// Create a tarantool user. Grant it default privileges.
+    pub fn on_master_create_user(user_def: &UserDef) -> tarantool::Result<()> {
+        let sys_user = Space::from(SystemSpace::User);
 
-    // Tarantool expects auth info to be a map of form `{ method: data }`,
-    // and currently the simplest way to achieve this is to use a HashMap.
-    let auth_map = HashMap::from([(user_def.auth.method, &user_def.auth.data)]);
-    sys_user.insert(&(user_id, euid, &user_def.name, "user", auth_map, &[(); 0], 0))?;
+        // This impelemtation was copied from box.schema.user.create excluding the
+        // password hashing.
+        let user_id = user_def.id;
+        let euid = ::tarantool::session::euid()?;
 
-    let lua = ::tarantool::lua_state();
-    lua.exec_with("box.schema.user.grant(...)", (user_id, "public"))
+        // Tarantool expects auth info to be a map of form `{ method: data }`,
+        // and currently the simplest way to achieve this is to use a HashMap.
+        let auth_map = HashMap::from([(user_def.auth.method, &user_def.auth.data)]);
+        sys_user.insert(&(user_id, euid, &user_def.name, "user", auth_map, &[(); 0], 0))?;
+
+        let lua = ::tarantool::lua_state();
+        lua.exec_with("box.schema.user.grant(...)", (user_id, "public"))
+            .map_err(LuaError::from)?;
+        lua.exec_with(
+            "box.schema.user.grant(...)",
+            (user_id, "alter", "user", user_id),
+        )
+        .map_err(LuaError::from)?;
+        lua.exec_with(
+            "box.session.su('admin', box.schema.user.grant, ...)",
+            (
+                user_id,
+                "session,usage",
+                "universe",
+                tlua::Nil,
+                tlua::AsTable((("if_not_exists", true),)),
+            ),
+        )
         .map_err(LuaError::from)?;
-    lua.exec_with(
-        "box.schema.user.grant(...)",
-        (user_id, "alter", "user", user_id),
-    )
-    .map_err(LuaError::from)?;
-    lua.exec_with(
-        "box.session.su('admin', box.schema.user.grant, ...)",
-        (
-            user_id,
-            "session,usage",
-            "universe",
-            tlua::Nil,
-            tlua::AsTable((("if_not_exists", true),)),
-        ),
-    )
-    .map_err(LuaError::from)?;
 
-    Ok(())
-}
+        Ok(())
+    }
 
-/// Update a tarantool user's authentication details.
-pub fn acl_change_user_auth_on_master(user_id: UserId, auth: &AuthDef) -> tarantool::Result<()> {
-    const USER_FIELD_AUTH: i32 = 4;
-    const USER_FIELD_LAST_MODIFIED: i32 = 6;
-    let sys_user = Space::from(SystemSpace::User);
+    /// Update a tarantool user's authentication details.
+    pub fn on_master_change_user_auth(user_id: UserId, auth: &AuthDef) -> tarantool::Result<()> {
+        const USER_FIELD_AUTH: i32 = 4;
+        const USER_FIELD_LAST_MODIFIED: i32 = 6;
+        let sys_user = Space::from(SystemSpace::User);
 
-    // Tarantool expects auth info to be a map of form `{ method: data }`,
-    // and currently the simplest way to achieve this is to use a HashMap.
-    let auth_map = HashMap::from([(auth.method, &auth.data)]);
-    let mut ops = UpdateOps::with_capacity(2);
-    ops.assign(USER_FIELD_AUTH, auth_map)?;
-    ops.assign(USER_FIELD_LAST_MODIFIED, fiber::time() as u64)?;
-    sys_user.update(&[user_id], ops)?;
-    Ok(())
-}
+        // Tarantool expects auth info to be a map of form `{ method: data }`,
+        // and currently the simplest way to achieve this is to use a HashMap.
+        let auth_map = HashMap::from([(auth.method, &auth.data)]);
+        let mut ops = UpdateOps::with_capacity(2);
+        ops.assign(USER_FIELD_AUTH, auth_map)?;
+        ops.assign(USER_FIELD_LAST_MODIFIED, fiber::time() as u64)?;
+        sys_user.update(&[user_id], ops)?;
+        Ok(())
+    }
 
-/// Drop a tarantool user and any entities (spaces, etc.) owned by it.
-pub fn acl_drop_user_on_master(user_id: UserId) -> tarantool::Result<()> {
-    let lua = ::tarantool::lua_state();
-    lua.exec_with("box.schema.user.drop(...)", user_id)
-        .map_err(LuaError::from)?;
+    /// Drop a tarantool user and any entities (spaces, etc.) owned by it.
+    pub fn on_master_drop_user(user_id: UserId) -> tarantool::Result<()> {
+        let lua = ::tarantool::lua_state();
+        lua.exec_with("box.schema.user.drop(...)", user_id)
+            .map_err(LuaError::from)?;
 
-    Ok(())
-}
+        Ok(())
+    }
 
-/// Create a tarantool role.
-pub fn acl_create_role_on_master(role_def: &RoleDef) -> tarantool::Result<()> {
-    let sys_user = Space::from(SystemSpace::User);
+    /// Create a tarantool role.
+    pub fn on_master_create_role(role_def: &RoleDef) -> tarantool::Result<()> {
+        let sys_user = Space::from(SystemSpace::User);
 
-    // This impelemtation was copied from box.schema.role.create.
+        // This impelemtation was copied from box.schema.role.create.
 
-    // Tarantool expects auth info to be a map `{}`, and currently the simplest
-    // way to achieve this is to use a HashMap.
-    sys_user.insert(&(
-        role_def.id,
-        ::tarantool::session::euid()?,
-        &role_def.name,
-        "role",
-        HashMap::<(), ()>::new(),
-        &[(); 0],
-        0,
-    ))?;
+        // Tarantool expects auth info to be a map `{}`, and currently the simplest
+        // way to achieve this is to use a HashMap.
+        sys_user.insert(&(
+            role_def.id,
+            ::tarantool::session::euid()?,
+            &role_def.name,
+            "role",
+            HashMap::<(), ()>::new(),
+            &[(); 0],
+            0,
+        ))?;
 
-    Ok(())
-}
+        Ok(())
+    }
 
-/// Drop a tarantool role and revoke it from anybody it was assigned to.
-pub fn acl_drop_role_on_master(role_id: UserId) -> tarantool::Result<()> {
-    let lua = ::tarantool::lua_state();
-    lua.exec_with("box.schema.role.drop(...)", role_id)
-        .map_err(LuaError::from)?;
+    /// Drop a tarantool role and revoke it from anybody it was assigned to.
+    pub fn on_master_drop_role(role_id: UserId) -> tarantool::Result<()> {
+        let lua = ::tarantool::lua_state();
+        lua.exec_with("box.schema.role.drop(...)", role_id)
+            .map_err(LuaError::from)?;
 
-    Ok(())
-}
+        Ok(())
+    }
 
-/// Grant a tarantool user some privilege defined by `priv_def`.
-pub fn acl_grant_privilege_on_master(priv_def: &PrivilegeDef) -> tarantool::Result<()> {
-    let lua = ::tarantool::lua_state();
-    lua.exec_with(
-        "local grantee_id, privilege, object_type, object_name = ...
-        local grantee_def = box.space._user:get(grantee_id)
-        if grantee_def.type == 'user' then
-            box.schema.user.grant(grantee_id, privilege, object_type, object_name)
-        else
-            box.schema.role.grant(grantee_id, privilege, object_type, object_name)
-        end",
-        (
-            priv_def.grantee_id,
-            &priv_def.privilege,
-            &priv_def.object_type,
-            &priv_def.object_name,
-        ),
-    )
-    .map_err(LuaError::from)?;
+    /// Grant a tarantool user some privilege defined by `priv_def`.
+    pub fn on_master_grant_privilege(priv_def: &PrivilegeDef) -> tarantool::Result<()> {
+        let lua = ::tarantool::lua_state();
+        lua.exec_with(
+            "local grantee_id, privilege, object_type, object_name = ...
+            local grantee_def = box.space._user:get(grantee_id)
+            if grantee_def.type == 'user' then
+                box.schema.user.grant(grantee_id, privilege, object_type, object_name)
+            else
+                box.schema.role.grant(grantee_id, privilege, object_type, object_name)
+            end",
+            (
+                priv_def.grantee_id,
+                &priv_def.privilege,
+                &priv_def.object_type,
+                &priv_def.object_name,
+            ),
+        )
+        .map_err(LuaError::from)?;
 
-    Ok(())
-}
+        Ok(())
+    }
 
-/// Revoke a privilege from a tarantool user.
-pub fn acl_revoke_privilege_on_master(priv_def: &PrivilegeDef) -> tarantool::Result<()> {
-    let lua = ::tarantool::lua_state();
-    lua.exec_with(
-        "local grantee_id, privilege, object_type, object_name = ...
-        local grantee_def = box.space._user:get(grantee_id)
-        if not grantee_def then
-            -- Grantee already dropped -> privileges already revoked
-            return
-        end
-        if grantee_def.type == 'user' then
-            box.schema.user.revoke(grantee_id, privilege, object_type, object_name)
-        else
-            box.schema.role.revoke(grantee_id, privilege, object_type, object_name)
-        end",
-        (
-            priv_def.grantee_id,
-            &priv_def.privilege,
-            &priv_def.object_type,
-            &priv_def.object_name,
-        ),
-    )
-    .map_err(LuaError::from)?;
+    /// Revoke a privilege from a tarantool user.
+    pub fn on_master_revoke_privilege(priv_def: &PrivilegeDef) -> tarantool::Result<()> {
+        let lua = ::tarantool::lua_state();
+        lua.exec_with(
+            "local grantee_id, privilege, object_type, object_name = ...
+            local grantee_def = box.space._user:get(grantee_id)
+            if not grantee_def then
+                -- Grantee already dropped -> privileges already revoked
+                return
+            end
+            if grantee_def.type == 'user' then
+                box.schema.user.revoke(grantee_id, privilege, object_type, object_name)
+            else
+                box.schema.role.revoke(grantee_id, privilege, object_type, object_name)
+            end",
+            (
+                priv_def.grantee_id,
+                &priv_def.privilege,
+                &priv_def.object_type,
+                &priv_def.object_name,
+            ),
+        )
+        .map_err(LuaError::from)?;
 
-    Ok(())
+        Ok(())
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/traft/node.rs b/src/traft/node.rs
index e392826fff3c19f6d2ef1b5db5c6beae53e84cf4..ab3e8f366380b281d0b5c286fcca188dbb001d10 100644
--- a/src/traft/node.rs
+++ b/src/traft/node.rs
@@ -13,16 +13,10 @@ use crate::loop_start;
 use crate::r#loop::FlowControl;
 use crate::rpc;
 use crate::schema::{Distribution, IndexDef, SpaceDef};
+use crate::storage::acl;
 use crate::storage::ddl_meta_drop_space;
 use crate::storage::SnapshotData;
 use crate::storage::ToEntryIter as _;
-use crate::storage::{
-    acl_change_user_auth_on_master, acl_create_role_on_master, acl_create_user_on_master,
-    acl_drop_role_on_master, acl_drop_user_on_master, acl_global_change_user_auth,
-    acl_global_create_role, acl_global_create_user, acl_global_drop_role, acl_global_drop_user,
-    acl_global_grant_privilege, acl_global_revoke_privilege, acl_grant_privilege_on_master,
-    acl_revoke_privilege_on_master,
-};
 use crate::storage::{ddl_abort_on_master, ddl_meta_space_update_operable};
 use crate::storage::{local_schema_version, set_local_schema_version};
 use crate::storage::{Clusterwide, ClusterwideSpaceId, PropertyName};
@@ -987,31 +981,31 @@ impl NodeImpl {
                     } else {
                         match &acl {
                             Acl::CreateUser { user_def } => {
-                                acl_create_user_on_master(user_def)
+                                acl::on_master_create_user(user_def)
                                     .expect("creating user shouldn't fail");
                             }
                             Acl::ChangeAuth { user_id, auth, .. } => {
-                                acl_change_user_auth_on_master(*user_id, auth)
+                                acl::on_master_change_user_auth(*user_id, auth)
                                     .expect("changing user auth shouldn't fail");
                             }
                             Acl::DropUser { user_id, .. } => {
-                                acl_drop_user_on_master(*user_id)
+                                acl::on_master_drop_user(*user_id)
                                     .expect("droping user shouldn't fail");
                             }
                             Acl::CreateRole { role_def } => {
-                                acl_create_role_on_master(role_def)
+                                acl::on_master_create_role(role_def)
                                     .expect("creating role shouldn't fail");
                             }
                             Acl::DropRole { role_id, .. } => {
-                                acl_drop_role_on_master(*role_id)
+                                acl::on_master_drop_role(*role_id)
                                     .expect("droping role shouldn't fail");
                             }
                             Acl::GrantPrivilege { priv_def } => {
-                                acl_grant_privilege_on_master(priv_def)
+                                acl::on_master_grant_privilege(priv_def)
                                     .expect("granting a privilege shouldn't fail");
                             }
                             Acl::RevokePrivilege { priv_def } => {
-                                acl_revoke_privilege_on_master(priv_def)
+                                acl::on_master_revoke_privilege(priv_def)
                                     .expect("revoking a privilege shouldn't fail");
                             }
                         }
@@ -1021,31 +1015,31 @@ impl NodeImpl {
 
                 match &acl {
                     Acl::CreateUser { user_def } => {
-                        acl_global_create_user(&self.storage, user_def)
+                        acl::global_create_user(&self.storage, user_def)
                             .expect("persisting a user definition shouldn't fail");
                     }
                     Acl::ChangeAuth { user_id, auth, .. } => {
-                        acl_global_change_user_auth(&self.storage, *user_id, auth)
+                        acl::global_change_user_auth(&self.storage, *user_id, auth)
                             .expect("changing user definition shouldn't fail");
                     }
                     Acl::DropUser { user_id, .. } => {
-                        acl_global_drop_user(&self.storage, *user_id)
+                        acl::global_drop_user(&self.storage, *user_id)
                             .expect("droping a user definition shouldn't fail");
                     }
                     Acl::CreateRole { role_def } => {
-                        acl_global_create_role(&self.storage, role_def)
+                        acl::global_create_role(&self.storage, role_def)
                             .expect("persisting a role definition shouldn't fail");
                     }
                     Acl::DropRole { role_id, .. } => {
-                        acl_global_drop_role(&self.storage, *role_id)
+                        acl::global_drop_role(&self.storage, *role_id)
                             .expect("droping a role definition shouldn't fail");
                     }
                     Acl::GrantPrivilege { priv_def } => {
-                        acl_global_grant_privilege(&self.storage, priv_def)
+                        acl::global_grant_privilege(&self.storage, priv_def)
                             .expect("persiting a privilege definition shouldn't fail");
                     }
                     Acl::RevokePrivilege { priv_def } => {
-                        acl_global_revoke_privilege(&self.storage, priv_def)
+                        acl::global_revoke_privilege(&self.storage, priv_def)
                             .expect("removing a privilege definition shouldn't fail");
                     }
                 }