Skip to content

Commit ca9a081

Browse files
committed
IAM | Principal validation and S3 permission updated with ID
Signed-off-by: Naveen Paul <[email protected]>
1 parent c0ac4c1 commit ca9a081

File tree

5 files changed

+56
-35
lines changed

5 files changed

+56
-35
lines changed

src/endpoint/s3/s3_rest.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ async function authorize_request_policy(req) {
251251
const account = req.object_sdk.requesting_account;
252252
const is_nc_deployment = req.object_sdk.nsfs_config_root;
253253
const account_identifier_name = is_nc_deployment ? account.name.unwrap() : account.email.unwrap();
254-
const account_identifier_id = is_nc_deployment ? account._id : undefined;
254+
// Both NSFS NC and containerized will validate bucket policy against acccount id.
255+
const account_identifier_id = account._id;
255256
const account_identifier_arn = s3_bucket_policy_utils.get_bucket_policy_principal_arn(account);
256257

257258
// deny delete_bucket permissions from bucket_claim_owner accounts (accounts that were created by OBC from openshift\k8s)
@@ -308,17 +309,18 @@ async function authorize_request_policy(req) {
308309
dbg.log3('authorize_request_policy: permission_by_id', permission_by_id);
309310
}
310311
if (permission_by_id === "DENY") throw new S3Error(S3Error.AccessDenied);
311-
if ((!account_identifier_id || permission_by_id !== "DENY") && account.owner === undefined) {
312+
// Check bucket policy permission against account name only for NSFS NC
313+
if (is_nc_deployment && permission_by_id !== "DENY" && account.owner === undefined) {
312314
permission_by_name = await s3_bucket_policy_utils.has_bucket_policy_permission(
313315
s3_policy, account_identifier_name, method, arn_path, req,
314316
{ disallow_public_access: public_access_block?.restrict_public_buckets }
315317
);
316318
dbg.log3('authorize_request_policy: permission_by_name', permission_by_name);
317319
}
318320
if (permission_by_name === "DENY") throw new S3Error(S3Error.AccessDenied);
319-
// Containerized deployment always will have account_identifier_id undefined
321+
// Check bucket policy permission against ARN only for containerized deployments.
320322
// Policy permission is validated by account arn
321-
if (!account_identifier_id) {
323+
if (!is_nc_deployment && permission_by_id !== "DENY") {
322324
permission_by_arn = await s3_bucket_policy_utils.has_bucket_policy_permission(
323325
s3_policy, account_identifier_arn, method, arn_path, req, public_access_block?.restrict_public_buckets
324326
);

src/server/system_services/bucket_server.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,9 @@ async function get_bucket_policy(req) {
523523
eg: arn:aws:iam::${account_id}:user/${iam_path}/${user_name}
524524
account email = ${iam_user_name}:${account_id}
525525
526-
@param {SensitiveString | String} principal Bucket policy principal
526+
@param {String} principal_as_string Bucket policy principal string
527527
*/
528-
async function get_account_by_principal(principal) {
529-
const principal_as_string = principal instanceof SensitiveString ? principal.unwrap() : principal;
528+
async function account_exists_by_principal_arn(principal_as_string) {
530529
const root_sufix = 'root';
531530
const user_sufix = 'user';
532531
const arn_parts = principal_as_string.split(':');
@@ -546,6 +545,27 @@ async function get_account_by_principal(principal) {
546545
//}
547546
}
548547

548+
/**
549+
Validate and return account by principal ARN and account id.
550+
551+
@param {SensitiveString | String} principal Bucket policy principal
552+
*/
553+
async function get_account_by_principal(principal) {
554+
const principal_as_string = principal instanceof SensitiveString ? principal.unwrap() : principal;
555+
const is_principal_arn = principal_as_string.startsWith('arn:aws:iam::');
556+
if (is_principal_arn) {
557+
const principal_by_arn = await account_exists_by_principal_arn(principal_as_string);
558+
dbg.log3('get_account_by_principal: principal_by_arn', principal_by_arn);
559+
if (principal_by_arn) return true;
560+
} else {
561+
const account = system_store.data.accounts.find(acc => acc._id.toString() === principal_as_string);
562+
const principal_by_id = account !== undefined;
563+
dbg.log3('get_account_by_principal: principal_by_id', principal_by_id);
564+
if (principal_by_id) return true;
565+
}
566+
return false;
567+
}
568+
549569
async function put_bucket_policy(req) {
550570
dbg.log0('put_bucket_policy:', req.rpc_params);
551571
const bucket = find_bucket(req, req.rpc_params.name);

src/test/integration_tests/api/iam/test_iam_basic_integration.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ mocha.describe('IAM basic integration tests - happy path', async function() {
7373
});
7474

7575
mocha.after(async () => {
76-
fs_utils.folder_delete(`${config_root}`);
76+
if (is_nc_coretest) {
77+
fs_utils.folder_delete(`${config_root}`);
78+
}
7779
});
7880

7981
mocha.describe('IAM User API', async function() {

src/test/integration_tests/api/s3/test_s3_bucket_policy.js

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ const cross_test_store = {};
6565
let user_a_account_details;
6666
let user_b_account_details;
6767

68+
let user_a_account_id;
69+
let user_b_account_id;
70+
6871
let admin_info;
69-
let account_info_a;
70-
let account_info_b;
7172

7273
let a_principal;
7374
let b_principal;
@@ -123,14 +124,14 @@ async function setup() {
123124
account.name = user_a;
124125
account.email = user_a;
125126
user_a_account_details = await rpc_client.account.create_account(account);
126-
account_info_a = user_a_account_details._id ? user_a_account_details : await rpc_client.account.read_account({ email: user_a });
127-
console.log('user_a_account_details', account_info_a);
127+
console.log('user_a_account_details', user_a_account_details);
128128
const user_a_keys = user_a_account_details.access_keys;
129+
user_a_account_id = is_nc_coretest ? user_a_account_details._id : user_a_account_details.id;
129130
account.name = user_b;
130131
account.email = user_b;
131132
user_b_account_details = await rpc_client.account.create_account(account);
132-
account_info_b = user_b_account_details._id ? user_b_account_details : await rpc_client.account.read_account({ email: user_b });
133-
console.log('user_b_account_details', account_info_b);
133+
console.log('user_b_account_details', user_b_account_details);
134+
user_b_account_id = is_nc_coretest ? user_b_account_details._id : user_b_account_details.id;
134135
const user_b_keys = user_b_account_details.access_keys;
135136
s3_creds.credentials = {
136137
accessKeyId: user_a_keys[0].access_key.unwrap(),
@@ -149,11 +150,11 @@ async function setup() {
149150
};
150151
/*
151152
For coretest nc, principal will have account name and
152-
+ for containerized deployment principal is ARN
153+
for containerized deployment principal is ARN
153154
*/
154155
admin_principal = is_nc_coretest ? EMAIL : s3_bucket_policy_utils.create_arn_for_root(admin_info._id.toString());
155-
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(account_info_a._id.toString());
156-
b_principal = is_nc_coretest ? user_b : s3_bucket_policy_utils.create_arn_for_root(account_info_b._id.toString());
156+
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_a_account_details.id.toString());
157+
b_principal = is_nc_coretest ? user_b : s3_bucket_policy_utils.create_arn_for_root(user_b_account_details.id.toString());
157158

158159
s3_owner = new S3(s3_creds);
159160
await s3_owner.createBucket({ Bucket: BKT });
@@ -312,12 +313,11 @@ mocha.describe('s3_bucket_policy', function() {
312313
});
313314

314315
mocha.it('should put/get bucket policy - principal by account ID', async function() {
315-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
316316
const policy = {
317317
Statement: [{
318-
Sid: `Allow all s3 actions on bucket ${BKT} to principal (by ID) ${user_a_account_details._id}`,
318+
Sid: `Allow all s3 actions on bucket ${BKT} to principal (by ID) ${user_a_account_id}`,
319319
Effect: 'Allow',
320-
Principal: { AWS: user_a_account_details._id },
320+
Principal: { AWS: user_a_account_id },
321321
Action: ['s3:*'],
322322
Resource: [`arn:aws:s3:::${BKT}`, `arn:aws:s3:::${BKT}/*`]
323323
}]
@@ -335,12 +335,11 @@ mocha.describe('s3_bucket_policy', function() {
335335
});
336336

337337
mocha.it('should put object to permitted account (bucket policy - principal by account ID', async function() {
338-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
339338
const policy = {
340339
Statement: [{
341-
Sid: `Allow all s3 actions on bucket ${BKT} to principal (by ID) ${user_a_account_details._id}`,
340+
Sid: `Allow all s3 actions on bucket ${BKT} to principal (by ID) ${user_a_account_id}`,
342341
Effect: 'Allow',
343-
Principal: { AWS: user_a_account_details._id },
342+
Principal: { AWS: user_a_account_id },
344343
Action: ['s3:*'],
345344
Resource: [`arn:aws:s3:::${BKT}`, `arn:aws:s3:::${BKT}/*`]
346345
}]
@@ -395,7 +394,7 @@ mocha.describe('s3_bucket_policy', function() {
395394
};
396395
}
397396
// Losing this value in-between, assigning it again
398-
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(account_info_a._id.toString());
397+
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_b_account_id.toString());
399398
const deny_account_by_name_all_s3_actions_statement = {
400399
Sid: `Do not allow user ${user_a} any s3 action`,
401400
Effect: 'Deny',
@@ -407,9 +406,8 @@ mocha.describe('s3_bucket_policy', function() {
407406
mocha.it('should not allow principal get object bucket policy with 2 statements: ' +
408407
'(1) DENY principal by account ID (2) ALLOW all principals as *', async function() {
409408
// in NC we allow principal to be also IDs
410-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
411409
const deny_account_by_id_all_s3_actions_statement =
412-
get_deny_account_by_id_all_s3_actions_statement(user_a_account_details._id);
410+
get_deny_account_by_id_all_s3_actions_statement(user_a_account_id);
413411
const policy = {
414412
Statement: [
415413
allow_all_principals_all_s3_actions_statement,
@@ -481,9 +479,9 @@ mocha.describe('s3_bucket_policy', function() {
481479
mocha.it('should not allow principal get object bucket policy with 2 statements: ' +
482480
'(1) DENY principal by account ID (2) ALLOW by account name', async function() {
483481
// in NC we allow principal to be also IDs
484-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
482+
// if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
485483
const deny_account_by_id_all_s3_actions_statement =
486-
get_deny_account_by_id_all_s3_actions_statement(user_a_account_details._id);
484+
get_deny_account_by_id_all_s3_actions_statement(user_a_account_id);
487485
const allow_account_by_name_all_s3_actions_statement = _.cloneDeep(deny_account_by_name_all_s3_actions_statement);
488486
allow_account_by_name_all_s3_actions_statement.Effect = 'Allow';
489487
allow_account_by_name_all_s3_actions_statement.Sid = `Allow user ${user_a} any s3 action`;
@@ -516,12 +514,12 @@ mocha.describe('s3_bucket_policy', function() {
516514
mocha.it('should not allow principal get object bucket policy with 2 statements: ' +
517515
'(1) DENY principal by account name (2) ALLOW by account ID', async function() {
518516
// in NC we allow principal to be also IDs
519-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
517+
// if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
520518
const deny_account_by_id_all_s3_actions_statement =
521-
get_deny_account_by_id_all_s3_actions_statement(user_a_account_details._id);
519+
get_deny_account_by_id_all_s3_actions_statement(user_a_account_id);
522520
const allow_account_by_id_all_s3_actions_statement = _.cloneDeep(deny_account_by_id_all_s3_actions_statement);
523521
allow_account_by_id_all_s3_actions_statement.Effect = 'Allow';
524-
allow_account_by_id_all_s3_actions_statement.Sid = `Allow user ${user_a_account_details._id} any s3 action`;
522+
allow_account_by_id_all_s3_actions_statement.Sid = `Allow user ${user_a_account_id} any s3 action`;
525523
const policy = {
526524
Statement: [
527525
deny_account_by_name_all_s3_actions_statement,
@@ -582,12 +580,12 @@ mocha.describe('s3_bucket_policy', function() {
582580
mocha.it('should not allow principal get object bucket policy with 2 statements: ' +
583581
'(1) ALLOW principal by account ID (2) DENY all principals as * (specific action only)', async function() {
584582
// in NC we allow principal to be also IDs
585-
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
583+
// if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
586584
const deny_account_by_id_all_s3_actions_statement =
587-
get_deny_account_by_id_all_s3_actions_statement(user_a_account_details._id);
585+
get_deny_account_by_id_all_s3_actions_statement(user_a_account_id);
588586
const allow_account_by_id_all_s3_actions_statement = _.cloneDeep(deny_account_by_id_all_s3_actions_statement);
589587
allow_account_by_id_all_s3_actions_statement.Effect = 'Allow';
590-
allow_account_by_id_all_s3_actions_statement.Sid = `Allow user ${user_a_account_details._id} any s3 action`;
588+
allow_account_by_id_all_s3_actions_statement.Sid = `Allow user ${user_a_account_id} any s3 action`;
591589
const policy = {
592590
Statement: [
593591
allow_account_by_id_all_s3_actions_statement,

src/util/account_util.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ function _check_root_account_owns_user(root_account, user_account) {
342342
return root_account_id === owner_account_id;
343343
}
344344

345-
346345
function _check_if_requesting_account_is_root_account(action, requesting_account, user_details = {}) {
347346
const is_root_account = _check_root_account(requesting_account);
348347
dbg.log1(`AccountSpaceNB.${action} requesting_account ID: ${requesting_account._id}` +

0 commit comments

Comments
 (0)