Skip to content

Commit 2920966

Browse files
oleg-jukovecDifferentialOrange
authored andcommitted
crud: add execution access to a VShard user
The patch adds execution access on a stroage for crud functions to a VShard storage user in the VShard manner [1]. 1. https://github.com/tarantool/vshard/blob/b3c27b32637863e9a03503e641bb7c8c69779a00/vshard/storage/init.lua#L777-L780 Closes #366
1 parent 3fe169b commit 2920966

30 files changed

+270
-107
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2222
* `crud.readview` resource cleanup on garbage collect (#379).
2323
* `doc/playground.lua` does not work with Tarantool 3 (#371).
2424
* Tests with Tarantool 3 (#364).
25+
* VShard storage user have not execution rights for internal functions (#366).
2526

2627
## [1.3.0] - 27-09-23
2728

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,14 @@ The CRUD operations should be called from router.
8686
All VShard storages should call `crud.init_storage()` after
8787
`vshard.storage.cfg()` (or enable the `crud-storage` role for Cartridge)
8888
first to initialize storage-side functions that are used to manipulate data
89-
across the cluster.
89+
across the cluster. The storage-side functions have the same access
90+
as a user calling `crud.init_storage()`. Therefore, if `crud` do not have
91+
enough access to modify some space, then you need to give access to the user.
9092

9193
All VShard routers should call `crud.init_router()` after `vshard.router.cfg()`
9294
(or enable the `crud-router` role for Cartridge) to make `crud` functions
93-
callable via `net.box`.
95+
callable via `net.box`. If a user is allowed to execute `crud` functions on
96+
the router-side then the user does not need additional access on storages.
9497

9598
You can check out an example of the configuration for local development
9699
(a single instance that combines router and storage) in

crud.lua

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ local stats = require('crud.stats')
2323
local readview = require('crud.readview')
2424
local schema = require('crud.schema')
2525

26+
local vshard = require('vshard')
27+
local luri = require('uri')
28+
2629
local crud = {}
2730

2831
-- @refer crud.version
@@ -165,28 +168,57 @@ crud.schema = schema.call
165168
-- @function init
166169
--
167170
function crud.init_storage()
171+
if type(box.cfg) ~= 'table' then
172+
error('box.cfg() must be called first')
173+
end
174+
175+
local user = nil
176+
if not box.info.ro then
177+
local ok, storage_info = pcall(vshard.storage.info)
178+
if not ok then
179+
error('vshard.storage.cfg() must be called first')
180+
end
181+
182+
local box_info = box.info()
183+
local replicaset_uuid
184+
if box_info.replicaset ~= nil then
185+
replicaset_uuid = box_info.replicaset.uuid
186+
else
187+
replicaset_uuid = box_info.cluster.uuid
188+
end
189+
local replicaset_info = storage_info.replicasets[replicaset_uuid]
190+
if replicaset_info == nil or replicaset_info.master == nil then
191+
error(string.format('Failed to find a vshard configuration for ' ..
192+
' replicaset with replicaset_uuid %s.',
193+
replicaset_uuid))
194+
end
195+
user = luri.parse(replicaset_info.master.uri).login or 'guest'
196+
end
197+
168198
if rawget(_G, '_crud') == nil then
169199
rawset(_G, '_crud', {})
170200
end
171201

172-
insert.init()
173-
insert_many.init()
174-
get.init()
175-
replace.init()
176-
replace_many.init()
177-
update.init()
178-
upsert.init()
179-
upsert_many.init()
180-
delete.init()
181-
select.init()
182-
truncate.init()
183-
len.init()
184-
count.init()
185-
borders.init()
186-
sharding_metadata.init()
187-
readview.init()
188-
189-
_G._crud.storage_info_on_storage = utils.storage_info_on_storage
202+
insert.init(user)
203+
insert_many.init(user)
204+
get.init(user)
205+
replace.init(user)
206+
replace_many.init(user)
207+
update.init(user)
208+
upsert.init(user)
209+
upsert_many.init(user)
210+
delete.init(user)
211+
select.init(user)
212+
truncate.init(user)
213+
len.init(user)
214+
count.init(user)
215+
borders.init(user)
216+
sharding_metadata.init(user)
217+
readview.init(user)
218+
219+
utils.init_storage_call(user, 'storage_info_on_storage',
220+
utils.storage_info_on_storage
221+
)
190222
end
191223

192224
function crud.init_router()

crud/borders.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ local BorderError = errors.new_class('BorderError', {capture_stack = false})
1313

1414
local borders = {}
1515

16-
local STAT_FUNC_NAME = '_crud.get_border_on_storage'
16+
local STAT_FUNC_NAME = 'get_border_on_storage'
17+
local CRUD_STAT_FUNC_NAME = utils.get_storage_call(STAT_FUNC_NAME)
1718

1819

1920
local function get_border_on_storage(border_name, space_name, index_id, field_names, fetch_latest_metadata)
@@ -42,8 +43,8 @@ local function get_border_on_storage(border_name, space_name, index_id, field_na
4243
})
4344
end
4445

45-
function borders.init()
46-
_G._crud.get_border_on_storage = get_border_on_storage
46+
function borders.init(user)
47+
utils.init_storage_call(user, STAT_FUNC_NAME, get_border_on_storage)
4748
end
4849

4950
local is_closer
@@ -111,7 +112,7 @@ local function call_get_border_on_router(vshard_router, border_name, space_name,
111112
timeout = opts.timeout,
112113
}
113114
local results, err, storages_info = call.map(vshard_router,
114-
STAT_FUNC_NAME,
115+
CRUD_STAT_FUNC_NAME,
115116
{border_name, space_name, index.id, field_names, opts.fetch_latest_metadata},
116117
call_opts
117118
)

crud/common/sharding/sharding_metadata.lua

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ local log = require('log')
44

55
local call = require('crud.common.call')
66
local const = require('crud.common.const')
7+
local utils = require('crud.common.utils')
78
local dev_checks = require('crud.common.dev_checks')
89
local router_cache = require('crud.common.sharding.router_metadata_cache')
910
local storage_cache = require('crud.common.sharding.storage_metadata_cache')
@@ -13,7 +14,8 @@ local sharding_utils = require('crud.common.sharding.utils')
1314

1415
local FetchShardingMetadataError = errors.new_class('FetchShardingMetadataError', {capture_stack = false})
1516

16-
local FETCH_FUNC_NAME = '_crud.fetch_on_storage'
17+
local FETCH_FUNC_NAME = 'fetch_on_storage'
18+
local CRUD_FETCH_FUNC_NAME = utils.get_storage_call(FETCH_FUNC_NAME)
1719

1820
local sharding_metadata_module = {}
1921

@@ -107,7 +109,7 @@ local _fetch_on_router = locked(function(vshard_router, space_name, metadata_map
107109
return
108110
end
109111

110-
local metadata_map, err = call.any(vshard_router, FETCH_FUNC_NAME, {}, {
112+
local metadata_map, err = call.any(vshard_router, CRUD_FETCH_FUNC_NAME, {}, {
111113
timeout = timeout
112114
})
113115
if err ~= nil then
@@ -212,8 +214,8 @@ function sharding_metadata_module.reload_sharding_cache(vshard_router, space_nam
212214
end
213215
end
214216

215-
function sharding_metadata_module.init()
216-
_G._crud.fetch_on_storage = sharding_metadata_module.fetch_on_storage
217+
function sharding_metadata_module.init(user)
218+
utils.init_storage_call(user, FETCH_FUNC_NAME, sharding_metadata_module.fetch_on_storage)
217219
end
218220

219221
return sharding_metadata_module

crud/common/utils.lua

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ local fiber = require('fiber')
2727

2828
local utils = {}
2929

30+
--- Returns a full call string for a storage function name.
31+
--
32+
-- @param string name a base name of the storage function.
33+
--
34+
-- @return a full string for the call.
35+
function utils.get_storage_call(name)
36+
dev_checks('string')
37+
38+
return '_crud.' .. name
39+
end
40+
41+
local CRUD_STORAGE_INFO_FUNC_NAME = utils.get_storage_call('storage_info_on_storage')
42+
3043
local space_format_cache = setmetatable({}, {__mode = 'k'})
3144

3245
-- copy from LuaJIT lj_char.c
@@ -1034,8 +1047,11 @@ function utils.update_storage_call_error_description(err, func_name, replicaset_
10341047
return nil
10351048
end
10361049

1037-
if err.type == 'ClientError' and type(err.message) == 'string' then
1038-
if err.message == string.format("Procedure '%s' is not defined", func_name) then
1050+
if (err.type == 'ClientError' or err.type == 'AccessDeniedError')
1051+
and type(err.message) == 'string' then
1052+
local not_defined_str = string.format("Procedure '%s' is not defined", func_name)
1053+
local access_denied_str = string.format("Execute access to function '%s' is denied", func_name)
1054+
if err.message == not_defined_str or err.message:startswith(access_denied_str) then
10391055
if func_name:startswith('_crud.') then
10401056
err = NotInitializedError:new("Function %s is not registered: " ..
10411057
"crud isn't initialized on replicaset %q or crud module versions mismatch " ..
@@ -1121,7 +1137,7 @@ function utils.storage_info(opts)
11211137
status = "error",
11221138
is_master = replicaset.master == replica
11231139
}
1124-
local ok, res = pcall(replica.conn.call, replica.conn, "_crud.storage_info_on_storage",
1140+
local ok, res = pcall(replica.conn.call, replica.conn, CRUD_STORAGE_INFO_FUNC_NAME,
11251141
{}, async_opts)
11261142
if ok then
11271143
futures_by_replicas[replica_uuid] = res
@@ -1177,6 +1193,30 @@ function utils.storage_info_on_storage()
11771193
return {status = "running"}
11781194
end
11791195

1196+
--- Initializes a storage function by its name.
1197+
--
1198+
-- It adds the function into the global scope by its name and required
1199+
-- access to a vshard storage user.
1200+
--
1201+
-- @function init_storage_call
1202+
--
1203+
-- @param string name of a user or nil if there is no need to setup access.
1204+
-- @param string name a name of the function.
1205+
-- @param function func the function.
1206+
--
1207+
-- @return nil
1208+
function utils.init_storage_call(user, name, func)
1209+
dev_checks('?string', 'string', 'function')
1210+
1211+
rawset(_G['_crud'], name, func)
1212+
1213+
if user ~= nil then
1214+
name = utils.get_storage_call(name)
1215+
box.schema.func.create(name, {setuid = true, if_not_exists = true})
1216+
box.schema.user.grant(user, 'execute', 'function', name, {if_not_exists=true})
1217+
end
1218+
end
1219+
11801220
local expected_vshard_api = {
11811221
'routeall', 'route', 'bucket_id_strcrc32',
11821222
'callrw', 'callro', 'callbro', 'callre',

crud/count.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ local compare_conditions = require('crud.compare.conditions')
1717

1818
local CountError = errors.new_class('CountError', {capture_stack = false})
1919

20-
local COUNT_FUNC_NAME = '_crud.count_on_storage'
20+
local COUNT_FUNC_NAME = 'count_on_storage'
21+
local CRUD_COUNT_FUNC_NAME = utils.get_storage_call(COUNT_FUNC_NAME)
2122

2223
local count = {}
2324

@@ -85,8 +86,8 @@ local function count_on_storage(space_name, index_id, conditions, opts)
8586
return tuples_count
8687
end
8788

88-
function count.init()
89-
_G._crud.count_on_storage = count_on_storage
89+
function count.init(user)
90+
utils.init_storage_call(user, COUNT_FUNC_NAME, count_on_storage)
9091
end
9192

9293
local check_count_safety_rl = ratelimit.new()
@@ -240,7 +241,7 @@ local function call_count_on_router(vshard_router, space_name, user_conditions,
240241
skip_sharding_hash_check = skip_sharding_hash_check,
241242
}
242243

243-
local results, err = call.map(vshard_router, COUNT_FUNC_NAME, {
244+
local results, err = call.map(vshard_router, CRUD_COUNT_FUNC_NAME, {
244245
space_name, plan.index_id, plan.conditions, count_opts
245246
}, call_opts)
246247

crud/delete.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ local DeleteError = errors.new_class('DeleteError', {capture_stack = false})
1414

1515
local delete = {}
1616

17-
local DELETE_FUNC_NAME = '_crud.delete_on_storage'
17+
local DELETE_FUNC_NAME = 'delete_on_storage'
18+
local CRUD_DELETE_FUNC_NAME = utils.get_storage_call(DELETE_FUNC_NAME)
1819

1920
local function delete_on_storage(space_name, key, field_names, opts)
2021
dev_checks('string', '?', '?table', {
@@ -51,8 +52,8 @@ local function delete_on_storage(space_name, key, field_names, opts)
5152
})
5253
end
5354

54-
function delete.init()
55-
_G._crud.delete_on_storage = delete_on_storage
55+
function delete.init(user)
56+
utils.init_storage_call(user, DELETE_FUNC_NAME, delete_on_storage)
5657
end
5758

5859
-- returns result, err, need_reload
@@ -127,7 +128,7 @@ local function call_delete_on_router(vshard_router, space_name, key, opts)
127128
}
128129

129130
local storage_result, err = call.single(vshard_router,
130-
bucket_id_data.bucket_id, DELETE_FUNC_NAME,
131+
bucket_id_data.bucket_id, CRUD_DELETE_FUNC_NAME,
131132
{space_name, key, opts.fields, delete_on_storage_opts},
132133
call_opts
133134
)

crud/get.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ local GetError = errors.new_class('GetError', {capture_stack = false})
1414

1515
local get = {}
1616

17-
local GET_FUNC_NAME = '_crud.get_on_storage'
17+
local GET_FUNC_NAME = 'get_on_storage'
18+
local CRUD_GET_FUNC_NAME = utils.get_storage_call(GET_FUNC_NAME)
1819

1920
local function get_on_storage(space_name, key, field_names, opts)
2021
dev_checks('string', '?', '?table', {
@@ -49,8 +50,8 @@ local function get_on_storage(space_name, key, field_names, opts)
4950
})
5051
end
5152

52-
function get.init()
53-
_G._crud.get_on_storage = get_on_storage
53+
function get.init(user)
54+
utils.init_storage_call(user, GET_FUNC_NAME, get_on_storage)
5455
end
5556

5657
-- returns result, err, need_reload
@@ -125,7 +126,7 @@ local function call_get_on_router(vshard_router, space_name, key, opts)
125126
}
126127

127128
local storage_result, err = call.single(vshard_router,
128-
bucket_id_data.bucket_id, GET_FUNC_NAME,
129+
bucket_id_data.bucket_id, CRUD_GET_FUNC_NAME,
129130
{space_name, key, opts.fields, get_on_storage_opts},
130131
call_opts
131132
)

crud/insert.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ local InsertError = errors.new_class('InsertError', {capture_stack = false})
1212

1313
local insert = {}
1414

15-
local INSERT_FUNC_NAME = '_crud.insert_on_storage'
15+
local INSERT_FUNC_NAME = 'insert_on_storage'
16+
local CRUD_INSERT_FUNC_NAME = utils.get_storage_call(INSERT_FUNC_NAME)
1617

1718
local function insert_on_storage(space_name, tuple, opts)
1819
dev_checks('string', 'table', {
@@ -52,8 +53,8 @@ local function insert_on_storage(space_name, tuple, opts)
5253
})
5354
end
5455

55-
function insert.init()
56-
_G._crud.insert_on_storage = insert_on_storage
56+
function insert.init(user)
57+
utils.init_storage_call(user, INSERT_FUNC_NAME, insert_on_storage)
5758
end
5859

5960
-- returns result, err, need_reload
@@ -102,7 +103,7 @@ local function call_insert_on_router(vshard_router, space_name, original_tuple,
102103
}
103104

104105
local storage_result, err = call.single(vshard_router,
105-
sharding_data.bucket_id, INSERT_FUNC_NAME,
106+
sharding_data.bucket_id, CRUD_INSERT_FUNC_NAME,
106107
{space_name, tuple, insert_on_storage_opts},
107108
call_opts
108109
)

0 commit comments

Comments
 (0)