Skip to content

Commit 60824f7

Browse files
committed
IAM | Bucket policy Principal upgrade script.
1 parent 69e29e1 commit 60824f7

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed

src/endpoint/s3/s3_rest.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ async function authorize_request_policy(req) {
241241
public_access_block,
242242
} = await req.object_sdk.read_bucket_sdk_policy_info(req.params.bucket);
243243

244+
console.log("authorize_request_policy ====>>>", bucket_owner, owner_account);
245+
244246
const auth_token = req.object_sdk.get_auth_token();
245247
const arn_path = _get_arn_from_req_path(req);
246248
const method = _get_method_from_req(req);

src/test/integration_tests/internal/test_upgrade_scripts.js

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
// setup coretest first to prepare the env
55
const _ = require('lodash');
66
const coretest = require('../../utils/coretest/coretest');
7-
const { rpc_client, EMAIL } = coretest;
7+
const { rpc_client, EMAIL, POOL_LIST } = coretest;
88
coretest.setup({ pools_to_create: [coretest.POOL_LIST[1]] });
99
const { S3 } = require('@aws-sdk/client-s3');
1010
const { NodeHttpHandler } = require("@smithy/node-http-handler");
1111
const http = require('http');
12+
const SensitiveString = require('../../../util/sensitive_string');
1213
const system_store = require('../../../server/system_services/system_store').get_instance();
1314
const upgrade_bucket_policy = require('../../../upgrade/upgrade_scripts/5.15.6/upgrade_bucket_policy');
15+
const upgrade_bucket_policy_principal = require('../../../upgrade/upgrade_scripts/5.21.0/upgrade_bucket_policy_principal');
1416
const upgrade_bucket_cors = require('../../../upgrade/upgrade_scripts/5.19.0/upgrade_bucket_cors');
1517
const remove_mongo_pool = require('../../../upgrade/upgrade_scripts/5.20.0/remove_mongo_pool');
1618
const dbg = require('../../../util/debug_module')(__filename);
@@ -199,6 +201,80 @@ mocha.describe('test upgrade scripts', async function() {
199201
assert.strictEqual(updated_bucket.tiering.tiers[0].tier.mirrors[0].spread_pools[0].name, default_pool_name);
200202
});
201203

204+
mocha.it('test upgrade bucket policy to ARN version 5.21.0', async function() {
205+
const iam_username = 'iam_username';
206+
const old_policy = {
207+
Version: '2012-10-17',
208+
Statement: [{
209+
Sid: 'id-1',
210+
Effect: 'Allow',
211+
Principal: {
212+
"AWS": [new SensitiveString(EMAIL)],
213+
},
214+
Action: ['s3:GetObject', 's3:*'],
215+
Resource: [`arn:aws:s3:::*`]
216+
},
217+
{
218+
Effect: 'Deny',
219+
Principal: {
220+
"AWS": [new SensitiveString(iam_username)],
221+
},
222+
Action: ['s3:PutObject'],
223+
Resource: [`arn:aws:s3:::*`]
224+
},
225+
]
226+
};
227+
// clean all leftover bucket policies as upgrade script doesn't work on updated policies
228+
await _clean_all_bucket_policies();
229+
230+
const bucket = system_store.data.buckets.find(bucket_obj => bucket_obj.name.unwrap() === BKT);
231+
await system_store.make_changes({
232+
update: {
233+
buckets: [{
234+
_id: bucket._id,
235+
s3_policy: old_policy
236+
}]
237+
}
238+
});
239+
const account = system_store.data.accounts.find(acc => acc.email.unwrap() === EMAIL);
240+
const nsr = 's3_bucket_policy_nsr';
241+
const iam_acc = {
242+
name: iam_username,
243+
email: iam_username,
244+
has_login: false,
245+
s3_access: true,
246+
default_resource: process.env.NC_CORETEST ? nsr : POOL_LIST[1].name,
247+
};
248+
await rpc_client.account.create_account(iam_acc);
249+
250+
const iam_account = system_store.data.accounts.find(acc => acc.email.unwrap() === iam_username);
251+
await system_store.make_changes({
252+
update: {
253+
accounts: [{
254+
_id: iam_account._id,
255+
owner: account._id.toString(),
256+
}]
257+
}
258+
});
259+
260+
await upgrade_bucket_policy_principal.run({ dbg, system_store, system_server: null });
261+
const res = await s3.getBucketPolicy({ // should work - bucket policy should fit current schema
262+
Bucket: BKT,
263+
});
264+
const new_policy = JSON.parse(res.Policy);
265+
266+
assert.strictEqual(new_policy.Statement.length, old_policy.Statement.length);
267+
assert.strictEqual(new_policy.Version, old_policy.Version);
268+
assert.strictEqual(new_policy.Statement[0].Sid, old_policy.Statement[0].Sid);
269+
assert.strictEqual(new_policy.Statement[0].Effect, 'Allow');
270+
assert.strictEqual(new_policy.Statement[0].Action[0], 's3:GetObject');
271+
assert.strictEqual(new_policy.Statement[0].Action[1], 's3:*');
272+
assert.strictEqual(new_policy.Statement[0].Resource[0], old_policy.Statement[0].Resource[0]);
273+
274+
assert.strictEqual(new_policy.Statement[0].Principal.AWS[0], `aws:arn:${account._id.toString()}:root`);
275+
assert.strictEqual(new_policy.Statement[1].Principal.AWS[0], `aws:arn:${iam_account._id.toString()}:user/${iam_account.email.unwrap()}`);
276+
});
277+
202278
mocha.after(async function() {
203279
await s3.deleteBucket({ Bucket: BKT });
204280
await s3.deleteBucket({ Bucket: BKT1 });
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* Copyright (C) 2023 NooBaa */
2+
"use strict";
3+
4+
const util = require('util');
5+
const _ = require('lodash');
6+
7+
const iam_constants = require('../../../endpoint/iam/iam_constants');
8+
9+
function _create_arn(dbg, principals, system_store) {
10+
if (!principals.AWS) return;
11+
const principal_arns = [];
12+
for (const principal of principals.AWS) {
13+
if (principal === '*') continue;
14+
const account = system_store.data.accounts.find(acc => acc.email.unwrap() === principal.unwrap());
15+
if (!account) {
16+
dbg.log0(`Could not found the account with email: ${principal}`);
17+
continue;
18+
}
19+
let arn;
20+
if (account.owner) {
21+
const iam_path = account.iam_path || iam_constants.IAM_DEFAULT_PATH;
22+
arn = `aws:arn:${account._id.toString()}:user${iam_path}${account.email.unwrap()}`;
23+
} else {
24+
arn = `aws:arn:${account._id.toString()}:root`;
25+
}
26+
principal_arns.push(arn);
27+
}
28+
return { AWS: principal_arns };
29+
}
30+
31+
async function run({ dbg, system_store, system_server }) {
32+
try {
33+
dbg.log0('Starting bucket policy Principal upgrade...');
34+
const buckets = [];
35+
for (const bucket of system_store.data.buckets) {
36+
// Do not update if there are no bucket policy.
37+
if (!bucket.s3_policy) continue;
38+
if (!_.isUndefined(bucket.s3_policy.Statement)) {
39+
const new_policy = bucket.s3_policy;
40+
new_policy.Statement = bucket.s3_policy.Statement.map(statement => ({
41+
Sid: statement.Sid,
42+
Effect: statement.Effect,
43+
Action: statement.Action,
44+
Resource: statement.Resource,
45+
Principal: _create_arn(dbg, statement.Principal, system_store),
46+
}));
47+
buckets.push({
48+
_id: bucket._id,
49+
s3_policy: new_policy,
50+
});
51+
}
52+
}
53+
54+
if (buckets.length > 0) {
55+
dbg.log0(`Replacing bucket policy Principal : ${buckets.map(bucket => util.inspect(bucket)).join(', ')}`);
56+
await system_store.make_changes({ update: { buckets } });
57+
} else {
58+
dbg.log0('Upgrading buckets policy Principal: no upgrade needed...');
59+
}
60+
61+
} catch (err) {
62+
dbg.error('Got error while upgrading buckets policy Principal:', err);
63+
throw err;
64+
}
65+
}
66+
67+
68+
module.exports = {
69+
run,
70+
description: 'Update bucket policy Principal to ARN formate'
71+
};

0 commit comments

Comments
 (0)