Skip to content

Commit e634e18

Browse files
committed
nc - iam - enable inline, cloudera test
Signed-off-by: Amit Prinz Setter <alphaprinz@gmail.com>
1 parent 350b703 commit e634e18

3 files changed

Lines changed: 207 additions & 10 deletions

File tree

src/endpoint/iam/iam_utils.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,9 +1408,6 @@ async function authorize_request_iam_policy_impl(req, method, bucket_name, servi
14081408
return deny_result;
14091409
}
14101410
if (iam_policies.length === 0) {
1411-
// TODO: remove NC empty-policy allow when PutRolePolicy (Phase 2) is implemented
1412-
// NC: IAM user / role inline policies are Phase 2; allow until PutRolePolicy exists
1413-
if (req.object_sdk.nsfs_config_root && (is_iam_user || is_assumed_role_session)) return true;
14141411
dbg.error('authorize_request_iam_policy:', iam_identity, 'has no inline policies configured');
14151412
return deny_result;
14161413
}

src/sdk/accountspace_fs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ class AccountSpaceFS {
917917
this._check_if_requesting_account_is_root_account(action, requesting_account, {});
918918
const { owner_account_id, role_data } = await this._check_if_role_exists(params, requesting_account);
919919
const iam_role_policies = [...(role_data.iam_user_policies || [])];
920-
const policy_index = this._check_iam_policy_exists(action, iam_role_policies, params.policy_name);
920+
const policy_index = this._check_iam_policy_exists(action, iam_role_policies, params.policy_name, 'role');
921921
iam_role_policies.splice(policy_index, 1);
922922
role_data.iam_user_policies = iam_role_policies;
923923
await this.config_fs.update_role_config_file(role_data);

src/test/integration_tests/api/sts/test_sts.js

Lines changed: 206 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
const { require_coretest, is_nc_coretest, generate_iam_client,
66
generate_s3_client, generate_sts_client, err_code } = require('../../../system_tests/test_utils');
77
const coretest = require_coretest();
8-
coretest.setup();
8+
99
const path = require('path');
1010
const fs = require('fs');
1111
const mocha = require('mocha');
@@ -19,10 +19,19 @@ const config = require('../../../../../config');
1919
const ldap_client = require('../../../../util/ldap_client');
2020
const { S3Error } = require('../../../../endpoint/s3/s3_errors');
2121
const { CreateRoleCommand, DeleteRoleCommand, DeleteRolePolicyCommand,
22-
PutRolePolicyCommand, UpdateAssumeRolePolicyCommand } = require('@aws-sdk/client-iam');
22+
PutRolePolicyCommand, UpdateAssumeRolePolicyCommand,
23+
CreateUserCommand, CreateAccessKeyCommand, DeleteAccessKeyCommand, DeleteUserCommand,
24+
PutUserPolicyCommand, DeleteUserPolicyCommand } = require('@aws-sdk/client-iam');
2325
const { AssumeRoleCommand, AssumeRoleWithWebIdentityCommand } = require('@aws-sdk/client-sts');
2426
const defualt_expiry_seconds = Math.ceil(config.STS_DEFAULT_SESSION_TOKEN_EXPIRY_MS / 1000);
2527

28+
29+
let setup_options;
30+
if (is_nc_coretest) {
31+
setup_options = { should_run_iam: true, https_port_iam: 7005, debug: 5 };
32+
}
33+
coretest.setup(setup_options);
34+
2635
const errors = {
2736
expired_token_s3: {
2837
code: S3Error.ExpiredToken.code,
@@ -887,8 +896,6 @@ mocha.describe('Assume role with web indentity tests', function() {
887896
});
888897

889898
mocha.describe('STS assumed-role IAM policy authorization tests', function() {
890-
if (is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
891-
892899
const { rpc_client } = coretest;
893900
const owner_email = 'role-authz-owner';
894901
const assumer_email = 'role-authz-assumer';
@@ -905,12 +912,20 @@ mocha.describe('STS assumed-role IAM policy authorization tests', function() {
905912
self.timeout(60000);
906913

907914
for (const account of accounts) {
908-
account.access_keys = (await rpc_client.account.create_account({
915+
let create_account_param = {
909916
has_login: false,
910917
s3_access: true,
911918
name: account.email,
912919
email: account.email,
913-
})).access_keys;
920+
};
921+
if (is_nc_coretest) {
922+
create_account_param.nsfs_account_config = {
923+
uid: process.getuid(),
924+
gid: process.getgid(),
925+
new_buckets_path: coretest.NC_CORETEST_STORAGE_PATH,
926+
};
927+
}
928+
account.access_keys = (await rpc_client.account.create_account(create_account_param)).access_keys;
914929
const access_key = account.access_keys[0].access_key.unwrap();
915930
const secret_key = account.access_keys[0].secret_key.unwrap();
916931
account.sts_client = generate_sts_client(access_key, secret_key, coretest.get_https_address_sts());
@@ -1013,3 +1028,188 @@ mocha.describe('STS assumed-role IAM policy authorization tests', function() {
10131028
assert.equal(response.$metadata.httpStatusCode, 200);
10141029
});
10151030
});
1031+
1032+
mocha.describe('Cloudera RAZ-style S3 role test', function() {
1033+
const { rpc_client } = coretest;
1034+
1035+
// account that owns the role and the bucket
1036+
const owner_email = 'raz-role-owner';
1037+
// IAM user (sub-user) under owner_email that will assume the role
1038+
const iam_username = 'raz-iam-user';
1039+
const role_name = 'RazS3Role';
1040+
const policy_name = 'RazS3InlinePolicy';
1041+
const bucket_name = 'raz-test-bucket';
1042+
const object_key = 'dummy-object.txt';
1043+
1044+
const owner = { email: owner_email };
1045+
let owner_account_info;
1046+
let iam_user_arn;
1047+
let iam_user_access_key_id;
1048+
let iam_user_secret_key;
1049+
1050+
const inline_policy = {
1051+
Version: '2012-10-17',
1052+
Statement: [
1053+
{
1054+
Effect: 'Allow',
1055+
Action: ['s3:GetBucketLocation', 's3:ListBucket'],
1056+
Resource: [`arn:aws:s3:::${bucket_name}`],
1057+
},
1058+
{
1059+
Effect: 'Allow',
1060+
Action: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject'],
1061+
Resource: [`arn:aws:s3:::${bucket_name}/*`],
1062+
},
1063+
],
1064+
};
1065+
1066+
mocha.after(async function() {
1067+
const self = this; // eslint-disable-line no-invalid-this
1068+
self.timeout(60000);
1069+
1070+
await owner.s3_client.deleteObject({ Bucket: bucket_name, Key: object_key });
1071+
await owner.s3_client.deleteBucket({ Bucket: bucket_name });
1072+
await owner.iam_client.send(new DeleteRolePolicyCommand({ RoleName: role_name, PolicyName: policy_name }));
1073+
await owner.iam_client.send(new DeleteRoleCommand({ RoleName: role_name }));
1074+
await owner.iam_client.send(new DeleteAccessKeyCommand({
1075+
UserName: iam_username,
1076+
AccessKeyId: iam_user_access_key_id,
1077+
}));
1078+
await owner.iam_client.send(new DeleteUserCommand({ UserName: iam_username }));
1079+
await rpc_client.account.delete_account({ email: owner_email });
1080+
});
1081+
1082+
mocha.before(async function() {
1083+
const self = this; // eslint-disable-line no-invalid-this
1084+
self.timeout(60000);
1085+
1086+
// 1. Create the owner account (NooBaa account that owns the role and bucket)
1087+
const create_account_param = {
1088+
has_login: false,
1089+
s3_access: true,
1090+
name: owner_email,
1091+
email: owner_email,
1092+
};
1093+
if (is_nc_coretest) {
1094+
create_account_param.nsfs_account_config = {
1095+
uid: process.getuid(),
1096+
gid: process.getgid(),
1097+
new_buckets_path: coretest.NC_CORETEST_STORAGE_PATH,
1098+
};
1099+
}
1100+
owner.access_keys = (await rpc_client.account.create_account(create_account_param)).access_keys;
1101+
owner_account_info = await rpc_client.account.read_account({ email: owner_email });
1102+
1103+
const access_key = owner.access_keys[0].access_key.unwrap();
1104+
const secret_key = owner.access_keys[0].secret_key.unwrap();
1105+
owner.iam_client = generate_iam_client(access_key, secret_key, coretest.get_https_address_iam());
1106+
owner.s3_client = generate_s3_client(access_key, secret_key, coretest.get_http_address());
1107+
1108+
// 2. Create an IAM user under the owner account
1109+
const create_user_resp = await owner.iam_client.send(new CreateUserCommand({ UserName: iam_username }));
1110+
iam_user_arn = create_user_resp.User.Arn;
1111+
1112+
// 3. Create access keys for the IAM user (step 2 of the test scenario)
1113+
const create_key_resp = await owner.iam_client.send(new CreateAccessKeyCommand({ UserName: iam_username }));
1114+
iam_user_access_key_id = create_key_resp.AccessKey.AccessKeyId;
1115+
iam_user_secret_key = create_key_resp.AccessKey.SecretAccessKey;
1116+
1117+
// 4. Create the bucket (step 3 of the test scenario)
1118+
await owner.s3_client.createBucket({ Bucket: bucket_name });
1119+
1120+
});
1121+
1122+
mocha.it('cloudera req with role', async function() {
1123+
1124+
// 5. Create the role with a trust policy allowing the IAM user to assume it (step 4)
1125+
const trust_policy = {
1126+
Version: '2012-10-17',
1127+
Statement: [{
1128+
Effect: 'Allow',
1129+
Principal: { AWS: [iam_user_arn] },
1130+
Action: ['sts:AssumeRole'],
1131+
}],
1132+
};
1133+
await owner.iam_client.send(new CreateRoleCommand({
1134+
RoleName: role_name,
1135+
AssumeRolePolicyDocument: JSON.stringify(trust_policy),
1136+
}));
1137+
1138+
// 6. Put the inline role policy granting the Cloudera RAZ-required S3 permissions
1139+
// on the created bucket (step 5 of the test scenario).
1140+
// Mirrors the "Storage prerequisites" S3 role policy from the Cloudera RAZ document:
1141+
// GetBucketLocation, ListBucket on the bucket; GetObject, PutObject, DeleteObject on objects.
1142+
await owner.iam_client.send(new PutRolePolicyCommand({
1143+
RoleName: role_name,
1144+
PolicyName: policy_name,
1145+
PolicyDocument: JSON.stringify(inline_policy),
1146+
}));
1147+
1148+
// 7. With the IAM user's credentials, assume the role (step 6 of the test scenario)
1149+
const owner_account_id = owner_account_info._id.toString();
1150+
const iam_user_sts = generate_sts_client(
1151+
iam_user_access_key_id,
1152+
iam_user_secret_key,
1153+
coretest.get_https_address_sts()
1154+
);
1155+
1156+
const assume_role_params = {
1157+
RoleArn: `arn:aws:sts::${owner_account_id}:role/${role_name}`,
1158+
RoleSessionName: 'raz-test-session',
1159+
};
1160+
const assume_resp = await iam_user_sts.send(new AssumeRoleCommand(assume_role_params));
1161+
const owner_key = owner.access_keys[0].access_key.unwrap();
1162+
const creds = validate_assume_role_response(
1163+
assume_resp,
1164+
`arn:aws:sts::${owner_account_id}:assumed-role/${role_name}/${assume_role_params.RoleSessionName}`,
1165+
`${owner_account_id}:${assume_role_params.RoleSessionName}`,
1166+
owner_key,
1167+
defualt_expiry_seconds
1168+
);
1169+
1170+
// 8. With the temporary credentials, put a dummy object in the bucket (step 7)
1171+
const temp_s3 = generate_s3_client(
1172+
creds.access_key,
1173+
creds.secret_key,
1174+
coretest.get_http_address(),
1175+
creds.session_token
1176+
);
1177+
const put_resp = await temp_s3.putObject({
1178+
Bucket: bucket_name,
1179+
Key: object_key,
1180+
Body: 'dummy content for raz test',
1181+
});
1182+
assert.equal(put_resp.$metadata.httpStatusCode, 200);
1183+
});
1184+
1185+
mocha.it('cloudera req with inline user policy', async function() {
1186+
const user_policy_name = 'RazS3UserInlinePolicy';
1187+
1188+
// Put the same Cloudera RAZ-required S3 permissions as an inline user policy
1189+
// directly on the IAM user — no role or assume-role involved.
1190+
await owner.iam_client.send(new PutUserPolicyCommand({
1191+
UserName: iam_username,
1192+
PolicyName: user_policy_name,
1193+
PolicyDocument: JSON.stringify(inline_policy),
1194+
}));
1195+
1196+
// Upload a dummy object directly with the IAM user's permanent credentials.
1197+
const iam_user_s3 = generate_s3_client(
1198+
iam_user_access_key_id,
1199+
iam_user_secret_key,
1200+
coretest.get_http_address()
1201+
);
1202+
const put_resp = await iam_user_s3.putObject({
1203+
Bucket: bucket_name,
1204+
Key: object_key,
1205+
Body: 'dummy content for raz user policy test',
1206+
});
1207+
assert.equal(put_resp.$metadata.httpStatusCode, 200);
1208+
1209+
// Clean up the inline user policy so after() doesn't leave stale state.
1210+
await owner.iam_client.send(new DeleteUserPolicyCommand({
1211+
UserName: iam_username,
1212+
PolicyName: user_policy_name,
1213+
}));
1214+
});
1215+
});

0 commit comments

Comments
 (0)