Skip to content

Commit 38c6b0d

Browse files
mandeseroTotktonada
authored andcommitted
config: grant runtime access to lua_call from config
This patch introduces the ability to grant execution privileges for Lua functions through declarative configuration, even when the database is in read-only mode or has an outdated schema version. Users can specify `lua_call: [<func_name>]`, enabling the execution of specified Lua functions (e.g., `failover:execute()` when all instance are in read-only mode). The `lua_call: [all]` option is also supported, allowing access to all global Lua functions except built-in ones, regardless of database mode or status. Privileges are still written to the database when possible for consistency and compatibility. Closes tarantool#10310 @TarantoolBot document Title: Grant runtime access to Lua functions via configuration It is now possible to grant execution privileges for Lua functions through the declarative configuration, even when the database is in read-only mode or has an outdated schema version. You can specify function permissions using the `lua_call` option in the configuration, for example: ```yaml credentials: users: alice: privileges: - permissions: [execute] lua_call: [my_func] ``` This grants the `alice` user permission to execute the `my_func` Lua function, regardless of the database's mode or status. The special option `lua_call: [all]` is also supported, granting access to all global Lua functions except built-in ones, bypassing database restrictions. Privileges will still be written to the database when possible to maintain compatibility and consistency with other privilege types.
1 parent db27af7 commit 38c6b0d

File tree

6 files changed

+363
-23
lines changed

6 files changed

+363
-23
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## feature/config
2+
3+
* Now users can specify the `lua_call` option to allow calling Lua functions
4+
even when the database is in read-only mode or has an outdated schema version
5+
(gh-10310).

src/box/CMakeLists.txt

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,30 @@ lua_source(lua_sources lua/iproto.lua iproto_lua)
4444
lua_source(lua_sources lua/mkversion.lua mkversion_lua)
4545

4646
# {{{ config
47-
lua_source(lua_sources lua/config/applier/app.lua config_applier_app_lua)
48-
lua_source(lua_sources lua/config/applier/box_cfg.lua config_applier_box_cfg_lua)
49-
lua_source(lua_sources lua/config/applier/compat.lua config_applier_compat_lua)
50-
lua_source(lua_sources lua/config/applier/console.lua config_applier_console_lua)
51-
lua_source(lua_sources lua/config/applier/credentials.lua config_applier_credentials_lua)
52-
lua_source(lua_sources lua/config/applier/fiber.lua config_applier_fiber_lua)
53-
lua_source(lua_sources lua/config/applier/mkdir.lua config_applier_mkdir_lua)
54-
lua_source(lua_sources lua/config/applier/roles.lua config_applier_roles_lua)
55-
lua_source(lua_sources lua/config/applier/sharding.lua config_applier_sharding_lua)
56-
lua_source(lua_sources lua/config/cluster_config.lua config_cluster_config_lua)
57-
lua_source(lua_sources lua/config/configdata.lua config_configdata_lua)
58-
lua_source(lua_sources lua/config/init.lua config_init_lua)
59-
lua_source(lua_sources lua/config/instance_config.lua config_instance_config_lua)
60-
lua_source(lua_sources lua/config/source/env.lua config_source_env_lua)
61-
lua_source(lua_sources lua/config/source/file.lua config_source_file_lua)
62-
lua_source(lua_sources lua/config/utils/aboard.lua config_utils_aboard_lua)
63-
lua_source(lua_sources lua/config/utils/expression.lua config_utils_expression_lua)
64-
lua_source(lua_sources lua/config/utils/file.lua config_utils_file_lua)
65-
lua_source(lua_sources lua/config/utils/log.lua config_utils_log_lua)
66-
lua_source(lua_sources lua/config/utils/odict.lua config_utils_odict_lua)
67-
lua_source(lua_sources lua/config/utils/schema.lua config_utils_schema_lua)
68-
lua_source(lua_sources lua/config/utils/snapshot.lua config_utils_snapshot_lua)
69-
lua_source(lua_sources lua/config/utils/tabulate.lua config_utils_tabulate_lua)
47+
lua_source(lua_sources lua/config/applier/app.lua config_applier_app_lua)
48+
lua_source(lua_sources lua/config/applier/box_cfg.lua config_applier_box_cfg_lua)
49+
lua_source(lua_sources lua/config/applier/runtime_priv.lua config_applier_runtime_priv_lua)
50+
lua_source(lua_sources lua/config/applier/compat.lua config_applier_compat_lua)
51+
lua_source(lua_sources lua/config/applier/console.lua config_applier_console_lua)
52+
lua_source(lua_sources lua/config/applier/credentials.lua config_applier_credentials_lua)
53+
lua_source(lua_sources lua/config/applier/fiber.lua config_applier_fiber_lua)
54+
lua_source(lua_sources lua/config/applier/mkdir.lua config_applier_mkdir_lua)
55+
lua_source(lua_sources lua/config/applier/roles.lua config_applier_roles_lua)
56+
lua_source(lua_sources lua/config/applier/sharding.lua config_applier_sharding_lua)
57+
lua_source(lua_sources lua/config/cluster_config.lua config_cluster_config_lua)
58+
lua_source(lua_sources lua/config/configdata.lua config_configdata_lua)
59+
lua_source(lua_sources lua/config/init.lua config_init_lua)
60+
lua_source(lua_sources lua/config/instance_config.lua config_instance_config_lua)
61+
lua_source(lua_sources lua/config/source/env.lua config_source_env_lua)
62+
lua_source(lua_sources lua/config/source/file.lua config_source_file_lua)
63+
lua_source(lua_sources lua/config/utils/aboard.lua config_utils_aboard_lua)
64+
lua_source(lua_sources lua/config/utils/expression.lua config_utils_expression_lua)
65+
lua_source(lua_sources lua/config/utils/file.lua config_utils_file_lua)
66+
lua_source(lua_sources lua/config/utils/log.lua config_utils_log_lua)
67+
lua_source(lua_sources lua/config/utils/odict.lua config_utils_odict_lua)
68+
lua_source(lua_sources lua/config/utils/schema.lua config_utils_schema_lua)
69+
lua_source(lua_sources lua/config/utils/snapshot.lua config_utils_snapshot_lua)
70+
lua_source(lua_sources lua/config/utils/tabulate.lua config_utils_tabulate_lua)
7071

7172
if (ENABLE_CONFIG_EXTRAS)
7273
lua_source(lua_sources ${CONFIG_EXTRAS_DIR}/source/etcd.lua config_source_etcd_lua)
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
-- Extract and add functions from a user or a role definition to
2+
-- the `{[func_name] = true, <...>}` mapping `res`.
3+
--
4+
-- The source is `lua_call` declarations.
5+
local function add_funcs(res, user_or_role_def)
6+
local privileges = user_or_role_def.privileges or {}
7+
8+
for _, privilege in ipairs(privileges) do
9+
local permissions = privilege.permissions or {}
10+
local has_execute = false
11+
for _, perm in ipairs(permissions) do
12+
if perm == 'execute' then
13+
has_execute = true
14+
break
15+
end
16+
end
17+
if has_execute and privilege.lua_call ~= nil then
18+
for _, func_name in ipairs(privilege.lua_call) do
19+
res[func_name] = true
20+
end
21+
end
22+
end
23+
end
24+
25+
-- Extract and add roles for the given user to the
26+
-- `{[role_name] = true, <...>}` mapping `res`, including
27+
-- transitively assigned (when a role is assigned to a role).
28+
local function add_roles(res, user_or_role_def, ctx)
29+
for _, role_name in ipairs(user_or_role_def.roles or {}) do
30+
-- Detect a recursion.
31+
if ctx.visited[role_name] then
32+
error(('Recursion detected: credentials.roles.%s depends on ' ..
33+
'itself'):format(role_name), 0)
34+
end
35+
36+
-- Add the role into the result.
37+
res[role_name] = true
38+
39+
-- Add the nested roles.
40+
--
41+
-- Ignore unknown roles. For example, there is a
42+
-- built-in role 'super' that doesn't have to be
43+
-- configured.
44+
local role_def = ctx.roles[role_name]
45+
if role_def ~= nil then
46+
ctx.visited[role_name] = true
47+
add_roles(res, role_def, ctx)
48+
ctx.visited[role_name] = nil
49+
end
50+
end
51+
end
52+
53+
-- Extract all the user's functions listed in the `lua_call`
54+
-- directives in the user definition or its roles assigned
55+
-- directly or transitively over the other roles.
56+
local function extract_funcs(user_name, ctx)
57+
local user_def = ctx.users[user_name]
58+
59+
local roles = {}
60+
ctx.visited = {}
61+
add_roles(roles, user_def, ctx)
62+
ctx.visited = nil
63+
64+
-- Collect a full set of functions for the given user.
65+
--
66+
-- {
67+
-- [func_name] = true,
68+
-- <...>,
69+
-- }
70+
local funcs = {}
71+
add_funcs(funcs, user_def)
72+
for role_name, _ in pairs(roles) do
73+
local role_def = ctx.roles[role_name]
74+
if role_def ~= nil then
75+
add_funcs(funcs, role_def)
76+
end
77+
end
78+
79+
return funcs
80+
end
81+
82+
local function apply(config_module)
83+
-- Prepare a context with the configuration information to
84+
-- transform.
85+
local configdata = config_module._configdata
86+
local ctx = {
87+
roles = configdata:get('credentials.roles') or {},
88+
users = configdata:get('credentials.users') or {},
89+
}
90+
91+
-- Collect a mapping from users to their granted functions.
92+
--
93+
-- {
94+
-- [user_name] = {
95+
-- [func_name] = true,
96+
-- <...>,
97+
-- },
98+
-- <...>
99+
-- }
100+
local res = {}
101+
for user_name, _ in pairs(ctx.users) do
102+
local funcs = extract_funcs(user_name, ctx)
103+
if next(funcs) ~= nil then
104+
res[user_name] = funcs
105+
end
106+
end
107+
108+
-- Reset the runtime privileges and grant all the configured
109+
-- ones.
110+
box.internal.lua_call_runtime_priv_reset()
111+
for user_name, funcs in pairs(res) do
112+
for func_name, _ in pairs(funcs) do
113+
if func_name == 'all' then
114+
box.internal.lua_call_runtime_priv_grant(user_name, '')
115+
else
116+
box.internal.lua_call_runtime_priv_grant(user_name, func_name)
117+
end
118+
end
119+
end
120+
end
121+
122+
return {
123+
name = 'runtime_priv',
124+
apply = apply,
125+
}

src/box/lua/config/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ function methods._initialize(self)
146146
self:_register_applier(require('internal.config.applier.compat'))
147147
self:_register_applier(require('internal.config.applier.mkdir'))
148148
self:_register_applier(require('internal.config.applier.console'))
149+
self:_register_applier(require('internal.config.applier.runtime_priv'))
149150
self:_register_applier(require('internal.config.applier.box_cfg'))
150151
self:_register_applier(require('internal.config.applier.credentials'))
151152
self:_register_applier(require('internal.config.applier.fiber'))

src/box/lua/init.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ extern char session_lua[],
151151
/* {{{ config */
152152
config_applier_app_lua[],
153153
config_applier_box_cfg_lua[],
154+
config_applier_runtime_priv_lua[],
154155
config_applier_compat_lua[],
155156
config_applier_console_lua[],
156157
config_applier_credentials_lua[],
@@ -426,6 +427,10 @@ static const char *lua_sources[] = {
426427
"internal.config.applier.console",
427428
config_applier_console_lua,
428429

430+
"config/applier/runtime_priv",
431+
"internal.config.applier.runtime_priv",
432+
config_applier_runtime_priv_lua,
433+
429434
"config/applier/credentials",
430435
"internal.config.applier.credentials",
431436
config_applier_credentials_lua,

0 commit comments

Comments
 (0)