Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NSFS | NC | add option to set account supplemental groups #8552

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/api/account_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ module.exports = {
uid: { type: 'number' },
gid: { type: 'number' },
new_buckets_path: { type: 'string' },
nsfs_only: { type: 'boolean' }
nsfs_only: { type: 'boolean' },
supplemental_groups: { type: 'string'},
}
},
},
Expand Down
3 changes: 2 additions & 1 deletion src/api/common_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,8 @@ module.exports = {
uid: { type: 'number' },
gid: { type: 'number' },
new_buckets_path: { type: 'string' },
nsfs_only: { type: 'boolean' }
nsfs_only: { type: 'boolean' },
supplemental_groups: { type: 'string'},
}
}, {
type: 'object',
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/manage_nsfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const { print_usage } = require('../manage_nsfs/manage_nsfs_help_utils');
const { TYPES, ACTIONS, LIST_ACCOUNT_FILTERS, LIST_BUCKET_FILTERS, GLACIER_ACTIONS } = require('../manage_nsfs/manage_nsfs_constants');
const { throw_cli_error, get_bucket_owner_account_by_name,
write_stdout_response, get_boolean_or_string_value, has_access_keys, set_debug_level,
is_name_update, is_access_key_update } = require('../manage_nsfs/manage_nsfs_cli_utils');
is_name_update, is_access_key_update, parse_comma_seperated_numbers_list } = require('../manage_nsfs/manage_nsfs_cli_utils');
const manage_nsfs_validations = require('../manage_nsfs/manage_nsfs_validations');
const nc_mkm = require('../manage_nsfs/nc_master_key_manager').get_instance();
const notifications_util = require('../util/notifications_util');
Expand Down Expand Up @@ -338,6 +338,7 @@ async function fetch_account_data(action, user_input) {
distinguished_name: user_input.user,
uid: user_input.user ? undefined : user_input.uid,
gid: user_input.user ? undefined : user_input.gid,
supplemental_groups: _.isUndefined(user_input.supplemental_groups) ? undefined : String(user_input.supplemental_groups),
new_buckets_path: user_input.new_buckets_path,
fs_backend: user_input.fs_backend ? String(user_input.fs_backend) : config.NSFS_NC_STORAGE_BACKEND
}
Expand Down
5 changes: 5 additions & 0 deletions src/manage_nsfs/manage_nsfs_cli_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,11 @@ ManageCLIError.InvalidGlacierOperation = Object.freeze({
message: 'only "migrate", "restore" and "expiry" subcommands are supported',
http_code: 400,
});
ManageCLIError.InvalidSupplementalGroupsList = Object.freeze({
code: 'InvalidSupplementalGroupsList',
message: 'supplemental groups must be a list of comma seperated numbers',
http_code: 400,
});


////////////////////////
Expand Down
10 changes: 9 additions & 1 deletion src/manage_nsfs/manage_nsfs_cli_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ function get_boolean_or_string_value(value) {
}
}

function parse_comma_seperated_numbers_list(value) {
if (typeof value === 'number') {
return [value];
}
return value.split(',').map(Number);
}

/**
* get_options_from_file will read a JSON file that include key-value of the options
* get_options_from_file will read a JSON file that include key-value of the options
* (instead of flags) and return its content
* @param {string} file_path
*/
Expand Down Expand Up @@ -156,6 +163,7 @@ function is_access_key_update(data) {
exports.throw_cli_error = throw_cli_error;
exports.write_stdout_response = write_stdout_response;
exports.get_boolean_or_string_value = get_boolean_or_string_value;
exports.parse_comma_seperated_numbers_list = parse_comma_seperated_numbers_list;
exports.get_bucket_owner_account_by_name = get_bucket_owner_account_by_name;
exports.get_bucket_owner_account_by_id = get_bucket_owner_account_by_id;
exports.get_options_from_file = get_options_from_file;
Expand Down
8 changes: 4 additions & 4 deletions src/manage_nsfs/manage_nsfs_constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ const FROM_FILE = 'from_file';
const ANONYMOUS = 'anonymous';

const VALID_OPTIONS_ACCOUNT = {
'add': new Set(['name', 'uid', 'gid', 'new_buckets_path', 'user', 'access_key', 'secret_key', 'fs_backend', 'allow_bucket_creation', 'force_md5_etag', 'iam_operate_on_root_account', FROM_FILE, ...CLI_MUTUAL_OPTIONS]),
'update': new Set(['name', 'uid', 'gid', 'new_buckets_path', 'user', 'access_key', 'secret_key', 'fs_backend', 'allow_bucket_creation', 'force_md5_etag', 'iam_operate_on_root_account', 'new_name', 'regenerate', ...CLI_MUTUAL_OPTIONS]),
'add': new Set(['name', 'uid', 'gid', 'supplemental_groups', 'new_buckets_path', 'user', 'access_key', 'secret_key', 'fs_backend', 'allow_bucket_creation', 'force_md5_etag', 'iam_operate_on_root_account', FROM_FILE, ...CLI_MUTUAL_OPTIONS]),
'update': new Set(['name', 'uid', 'gid', 'supplemental_groups', 'new_buckets_path', 'user', 'access_key', 'secret_key', 'fs_backend', 'allow_bucket_creation', 'force_md5_etag', 'iam_operate_on_root_account', 'new_name', 'regenerate', ...CLI_MUTUAL_OPTIONS]),
'delete': new Set(['name', ...CLI_MUTUAL_OPTIONS]),
'list': new Set(['wide', 'show_secrets', 'gid', 'uid', 'user', 'name', 'access_key', ...CLI_MUTUAL_OPTIONS]),
'status': new Set(['name', 'access_key', 'show_secrets', ...CLI_MUTUAL_OPTIONS]),
};

const VALID_OPTIONS_ANONYMOUS_ACCOUNT = {
'add': new Set(['uid', 'gid', 'user', 'anonymous', ...CLI_MUTUAL_OPTIONS]),
'update': new Set(['uid', 'gid', 'user', 'anonymous', ...CLI_MUTUAL_OPTIONS]),
'add': new Set(['uid', 'gid', 'supplemental_groups', 'user', 'anonymous', ...CLI_MUTUAL_OPTIONS]),
'update': new Set(['uid', 'gid', 'supplemental_groups', 'user', 'anonymous', ...CLI_MUTUAL_OPTIONS]),
'delete': new Set(['anonymous', ...CLI_MUTUAL_OPTIONS]),
'status': new Set(['anonymous', ...CLI_MUTUAL_OPTIONS]),
};
Expand Down
6 changes: 4 additions & 2 deletions src/manage_nsfs/manage_nsfs_help_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Flags:
--name <string> Set the name for the account
--uid <number> Set the User Identifier (UID) (UID and GID can be replaced by --user option)
--gid <number> Set the Group Identifier (GID) (UID and GID can be replaced by --user option)
--supplemental_groups <string> (optional) Set the supplemntal group list (List of GID) seperated by comma (,)
--new_buckets_path <string> (optional) Set the filesystem's root path where each subdirectory is a bucket
--user <string> (optional) Set the OS user name (instead of UID and GID)
--access_key <string> (optional) Set the access key for the account (default is generated)
Expand All @@ -98,6 +99,7 @@ Flags:
--new_name <string> (optional) Update the account name
--uid <number> (optional) Update the User Identifier (UID)
--gid <number> (optional) Update the Group Identifier (GID)
--supplemental_groups <string> (optional) Update the list of supplemental groups (List of GID) seperated by comma('). will override existing list
--new_buckets_path <string> (optional) Update the filesystem's root path where each subdirectory is a bucket
--user <string> (optional) Update the OS user name (instead of uid and gid)
--regenerate (optional) Update automatically generated access key and secret key
Expand Down Expand Up @@ -303,13 +305,13 @@ But updates of the config directory will be blocked during the upgrade of the co
'upgrade start' should be executed on one node, the config directory changes will be available for all the nodes of the cluster.

Usage:

noobaa-cli upgrade start [flags]

Flags:

--expected_version <string> The expected target version of the upgrade
--expected_hosts <string> The expected hosts running NooBaa NC, a string of hosts separated by ,
--expected_hosts <string> The expected hosts running NooBaa NC, a string of hosts separated by ,
--skip_verification <boolean> (optional) skip verification of the hosts package version
WARNING: can cause corrupted config dir files created by hosts running old code
--custom_upgrade_scripts_dir <string> (optional) custom upgrade scripts dir, use for running custom config dir upgrade scripts
Expand Down
19 changes: 18 additions & 1 deletion src/manage_nsfs/manage_nsfs_validations.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ function validate_options_type_by_value(input_options_with_data) {
if ((option === 'bucket_policy' || option === 'notifications') && type_of_value === 'object') {
continue;
}
const details = `type of flag ${option} should be ${type_of_option}`;
//special case for supplemental groups
if (option === 'supplemental_groups' && validate_supplemental_groups(value)) {
continue;
}
const details = `type of flag ${option} should be ${type_of_option} ${type_of_value} ${value}`;
throw_cli_error(ManageCLIError.InvalidArgumentType, details);
}
}
Expand All @@ -197,6 +201,19 @@ function validate_boolean_string_value(value) {
return false;
}

function validate_supplemental_groups(value) {
if (value && typeof value === 'string') {
const regex = /^[0-9]+(,[0-9]+)+$/;
if (!regex.test(value)) {
throw_cli_error(ManageCLIError.InvalidSupplementalGroupsList);
}
return true;
} else if (typeof value === 'number') {
return true;
}
return false;
}

/**
* validate_min_flags_for_update validates that we have at least one flag of a property to update
* @param {string} type
Expand Down
18 changes: 17 additions & 1 deletion src/native/fs/fs_napi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,17 @@ load_xattr_get_keys(Napi::Object& options, std::vector<std::string>& _xattr_get_
}
}

template<typename T>
static std::vector<T> convert_delimited_string_to_number_vector(const std::string str, const char delimiter) {
std::vector<T> new_vector;
std::stringstream sstream(str);
std::string item;
while (std::getline(sstream, item, delimiter)) {
new_vector.push_back(std::stoi(item));
}
return new_vector;
}

/**
* FSWorker is a general async worker for our fs operations
*/
Expand All @@ -560,6 +571,7 @@ struct FSWorker : public Napi::AsyncWorker
double _took_time;
Napi::FunctionReference _report_fs_stats;
bool _should_add_thread_capabilities;
std::vector<gid_t> _supplemental_groups;

// executes the ctime check in the stat and read file fuctions
// NOTE: If _do_ctime_check = false, then some functions will fallback to using mtime check
Expand All @@ -576,6 +588,7 @@ struct FSWorker : public Napi::AsyncWorker
, _warn_threshold_ms(0)
, _took_time(0)
, _should_add_thread_capabilities(false)
, _supplemental_groups()
, _do_ctime_check(false)
{
for (int i = 0; i < (int)info.Length(); ++i) _args_ref.Set(i, info[i]);
Expand All @@ -586,6 +599,9 @@ struct FSWorker : public Napi::AsyncWorker
if (fs_context.Get("backend").ToBoolean()) {
_backend = fs_context.Get("backend").ToString();
}
if(fs_context.Has("supplemental_groups")) {
_supplemental_groups = convert_delimited_string_to_number_vector<gid_t>(fs_context.Get("supplemental_groups").ToString(), ',');
}
if (fs_context.Get("warn_threshold_ms").ToBoolean()) {
_warn_threshold_ms = fs_context.Get("warn_threshold_ms").ToNumber();
}
Expand All @@ -606,7 +622,7 @@ struct FSWorker : public Napi::AsyncWorker
{
DBG1("FS::FSWorker::Execute: " << _desc << DVAL(_uid) << DVAL(_gid) << DVAL(_backend));
ThreadScope tx;
tx.set_user(_uid, _gid);
tx.set_user(_uid, _gid, &_supplemental_groups);
DBG1("FS::FSWorker::Execute: " << _desc << DVAL(_uid) << DVAL(_gid) << DVAL(geteuid()) << DVAL(getegid()) << DVAL(getuid()) << DVAL(getgid()));

if(_should_add_thread_capabilities) {
Expand Down
4 changes: 3 additions & 1 deletion src/native/util/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ class ThreadScope
restore_user();
}

void set_user(uid_t uid, gid_t gid)
void set_user(uid_t uid, gid_t gid, std::vector<gid_t>* groups)
{
_uid = uid;
_gid = gid;
_groups = groups;
change_user();
}

Expand All @@ -49,6 +50,7 @@ class ThreadScope
void restore_user();
uid_t _uid;
gid_t _gid;
std::vector<gid_t>* _groups;
};

} // namespace noobaa
11 changes: 9 additions & 2 deletions src/native/util/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,14 @@ const std::vector<gid_t> ThreadScope::orig_groups = [] {
void
ThreadScope::change_user()
{
if (_groups == NULL || _groups->empty()) {
MUST_SYS(syscall(SYS_setgroups, 0, NULL));
}
else if (_groups != NULL && *_groups != orig_groups) {
MUST_SYS(syscall(SYS_setgroups, _groups->size(), &_groups->at(0)));
}
if (_uid != orig_uid || _gid != orig_gid) {
// must change gid first otherwise will fail on permission
MUST_SYS(syscall(SYS_setgroups, 0, NULL));
MUST_SYS(syscall(SYS_setresgid, -1, _gid, -1));
MUST_SYS(syscall(SYS_setresuid, -1, _uid, -1));
}
Expand All @@ -61,7 +66,9 @@ ThreadScope::restore_user()
// must restore uid first otherwise will fail on permission
MUST_SYS(syscall(SYS_setresuid, -1, orig_uid, -1));
MUST_SYS(syscall(SYS_setresgid, -1, orig_gid, -1));
MUST_SYS(syscall(SYS_setgroups, ThreadScope::orig_groups.size(), &ThreadScope::orig_groups[0]));
if(_groups == NULL || orig_groups != *_groups) {
MUST_SYS(syscall(SYS_setgroups, orig_groups.size(), &orig_groups[0]));
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/sdk/nb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,7 @@ interface NativeFSContext {
uid?: number;
gid?: number;
backend?: string;
supplemental_groups?: string;
warn_threshold_ms?: number;
report_fs_stats?: Function;
do_ctime_check?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/server/system_services/schemas/nsfs_account_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ module.exports = {
properties: {
uid: { type: 'number' },
gid: { type: 'number' },
supplemental_groups: { type: 'string' },
new_buckets_path: { type: 'string' },
fs_backend: {
$ref: 'common_api#/definitions/fs_backend'
Expand Down
Loading
Loading