-
Notifications
You must be signed in to change notification settings - Fork 90
IAM | No Bucket Policy Authorization for IAM Users #9291
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
Conversation
WalkthroughAdds a new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant S3 as s3_rest.js
participant SDK as object_sdk.js
participant Bucket as bucket_server.js
participant Auth as auth_server.js
Client->>S3: authorize_request(request)
S3->>SDK: read_bucket_sdk_policy_info(bucket)
SDK->>Bucket: read_bucket_sdk_info(bucket)
Bucket-->>SDK: bucket info (includes bucket_owner_id)
SDK-->>S3: policy_info (includes bucket_owner_id, owner_account)
alt Bucket has policy
S3->>Auth: evaluate policy using owner_account
else No bucket policy
S3->>S3: determine is_nc_deployment
S3->>S3: owner_to_compare = is_nc_deployment ? owner_account.id : bucket_owner_id
S3->>Auth: has_bucket_action_permission(requester, owner_to_compare, ...)
end
Auth->>Auth: if no policy: allow if requester == owner OR requester.root_owner == bucket_owner_root
Auth-->>S3: permission result
S3-->>Client: authorized / denied
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/api/bucket_api.js(1 hunks)src/endpoint/s3/s3_rest.js(2 hunks)src/sdk/object_sdk.js(1 hunks)src/server/common_services/auth_server.js(1 hunks)src/server/system_services/bucket_server.js(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.
📚 Learning: 2025-11-12T04:55:42.193Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.
Applied to files:
src/api/bucket_api.jssrc/server/common_services/auth_server.jssrc/sdk/object_sdk.jssrc/endpoint/s3/s3_rest.jssrc/server/system_services/bucket_server.js
📚 Learning: 2025-11-18T07:00:17.636Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368
Timestamp: 2025-11-18T07:00:17.636Z
Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.
Applied to files:
src/endpoint/s3/s3_rest.js
📚 Learning: 2025-08-08T13:08:38.361Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9182
File: src/server/system_services/bucket_server.js:1324-1327
Timestamp: 2025-08-08T13:08:38.361Z
Learning: In src/server/system_services/bucket_server.js, the update_all_buckets_default_pool(req) handler expects req.rpc_params.pool_name to be a plain string (not a SensitiveString wrapper), so calling .unwrap() is not needed there.
Applied to files:
src/server/system_services/bucket_server.js
🧬 Code graph analysis (3)
src/server/common_services/auth_server.js (2)
src/endpoint/s3/s3_rest.js (5)
account(256-256)account(340-340)bucket(402-402)bucket(424-424)is_owner(272-285)src/endpoint/s3/s3_bucket_policy_utils.js (1)
account(293-293)
src/sdk/object_sdk.js (2)
src/endpoint/s3/s3_rest.js (2)
bucket(402-402)bucket(424-424)src/server/system_services/bucket_server.js (14)
bucket(350-350)bucket(364-364)bucket(383-383)bucket(401-401)bucket(426-426)bucket(438-438)bucket(453-453)bucket(489-489)bucket(498-498)bucket(511-511)bucket(551-551)bucket(577-577)bucket(596-596)bucket(610-610)
src/server/system_services/bucket_server.js (2)
src/server/object_services/object_server.js (4)
bucket(470-470)bucket(1394-1394)bucket(1483-1483)bucket(1529-1529)src/server/system_services/system_server.js (1)
bucket(237-242)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Noobaa Image
- GitHub Check: run-package-lock-validation
- GitHub Check: run-jest-unit-tests
🔇 Additional comments (5)
src/sdk/object_sdk.js (1)
221-221: LGTM: Bucket owner ID added to policy info.The new
bucket_owner_idfield is correctly added to the policy info payload, aligning with the bucket info response frombucket_server.js(line 736) where it's populated asbucket.owner_account._id.toString().src/api/bucket_api.js (1)
1210-1212: LGTM: Schema updated for bucket owner ID.The
bucket_owner_idfield is appropriately added to thebucket_sdk_infodefinition as a non-required string field, ensuring backward compatibility while supporting the new IAM authorization flow.src/server/system_services/bucket_server.js (1)
736-736: LGTM: Bucket owner ID populated correctly.The
bucket_owner_idfield is properly set frombucket.owner_account._id.toString(), which is safe since buckets always have an owner_account. This value flows correctly to the SDK layer and authorization logic.src/endpoint/s3/s3_rest.js (2)
290-291: LGTM: Account owner comparison handles string correctly.The comparison correctly treats
account.owneras a string (line 291), which aligns with the retrieved learning that account.owner fromreq.object_sdk.requesting_accountis already a string (account ID) from RPC serialization.Based on learnings
287-294: Fix type mismatch in owner ID comparison on line 290.When
nsfs_config_rootis true,owner_account?.idis an ObjectId (from bucket_server.js line 1521), but it's being compared againstaccount.ownerwhich is a string. This comparison will always fail. Line 290 should call.toString()on the ObjectId:const owner_id_to_compare = req.object_sdk.nsfs_config_root ? owner_account?.id?.toString() : bucket_owner_id;The
bucket_owner_idpath (line 736 of bucket_server.js) is already stringified, so only thensfs_config_rootpath requires the conversion.⛔ Skipped due to learnings
Learnt from: naveenpaul1 Repo: noobaa/noobaa-core PR: 9277 File: src/endpoint/s3/s3_rest.js:258-261 Timestamp: 2025-11-12T04:55:42.193Z Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.Learnt from: naveenpaul1 Repo: noobaa/noobaa-core PR: 9182 File: src/server/system_services/bucket_server.js:1324-1327 Timestamp: 2025-08-08T13:08:38.361Z Learning: In src/server/system_services/bucket_server.js, the update_all_buckets_default_pool(req) handler expects req.rpc_params.pool_name to be a plain string (not a SensitiveString wrapper), so calling .unwrap() is not needed there.Learnt from: naveenpaul1 Repo: noobaa/noobaa-core PR: 9277 File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368 Timestamp: 2025-11-18T07:00:17.636Z Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.Learnt from: shirady Repo: noobaa/noobaa-core PR: 9281 File: src/server/system_services/account_server.js:1053-1058 Timestamp: 2025-11-13T07:56:23.620Z Learning: In noobaa-core, account_server.js is only used in containerized deployments, not in NSFS/NC deployments. NSFS/NC deployments have separate account management code in src/manage_nsfs/ directory. Therefore, account_server.js only processes accounts from account_schema.js where owner is an objectid reference, never from nsfs_account_schema.js where owner is a string.
2d9b908 to
aa4124b
Compare
Signed-off-by: shirady <[email protected]>
aa4124b to
640cdd3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/api/bucket_api.js (1)
1192-1212: bucket_owner_id addition looks correct and backward‑compatibleAdding
bucket_owner_idas a string onbucket_sdk_infocleanly exposes the owner account ID without breaking existing callers (it’s not inrequired). Just ensure the producers ofbucket_sdk_infoconsistently set this field wherever IAM / owner‑ID based auth decisions depend on it.src/server/common_services/auth_server.js (1)
548-554: No‑policy IAM access logic matches intent; consider a slightly safer owner checkThe new
!bucket_policybranch correctly gives access to:
- the bucket owner / claim owner (
is_owner), and- IAM accounts whose
account.ownermatchesbucket.owner_account.This aligns with the PR’s goal of allowing IAM users under the bucket’s root account when no bucket policy exists. Based on learnings, using
account.owner._id.toString()here is appropriate sinceaccountis loaded fromsystem_storeandowneris an object ID reference, not a serialized string.To harden against unexpected shapes, you could defensively guard the comparison:
- const is_iam_and_same_root_account_owner = account.owner !== undefined && - account.owner._id.toString() === bucket.owner_account._id.toString(); + const is_iam_and_same_root_account_owner = account.owner && + account.owner._id && + bucket.owner_account && + bucket.owner_account._id && + account.owner._id.toString() === bucket.owner_account._id.toString();This avoids a possible runtime error if either side is ever nullish while preserving the intended semantics.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/api/bucket_api.js(1 hunks)src/endpoint/s3/s3_rest.js(3 hunks)src/sdk/object_sdk.js(1 hunks)src/server/common_services/auth_server.js(1 hunks)src/server/system_services/bucket_server.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/server/system_services/bucket_server.js
- src/endpoint/s3/s3_rest.js
- src/sdk/object_sdk.js
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.
📚 Learning: 2025-11-12T04:55:42.193Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.
Applied to files:
src/api/bucket_api.jssrc/server/common_services/auth_server.js
📚 Learning: 2025-11-19T15:03:42.231Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9291
File: src/server/common_services/auth_server.js:548-554
Timestamp: 2025-11-19T15:03:42.231Z
Learning: In src/server/common_services/auth_server.js, account objects are loaded directly from system_store (e.g., system_store.data.get_by_id()), so account.owner is an object ID reference with an ._id property, not a string. This differs from s3_rest.js where account.owner is a string due to RPC serialization.
Applied to files:
src/server/common_services/auth_server.js
📚 Learning: 2025-11-18T07:00:17.636Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368
Timestamp: 2025-11-18T07:00:17.636Z
Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.
Applied to files:
src/server/common_services/auth_server.js
📚 Learning: 2025-08-08T13:08:38.361Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9182
File: src/server/system_services/bucket_server.js:1324-1327
Timestamp: 2025-08-08T13:08:38.361Z
Learning: In src/server/system_services/bucket_server.js, the update_all_buckets_default_pool(req) handler expects req.rpc_params.pool_name to be a plain string (not a SensitiveString wrapper), so calling .unwrap() is not needed there.
Applied to files:
src/server/common_services/auth_server.js
📚 Learning: 2025-11-13T07:56:23.620Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9281
File: src/server/system_services/account_server.js:1053-1058
Timestamp: 2025-11-13T07:56:23.620Z
Learning: In noobaa-core, account_server.js is only used in containerized deployments, not in NSFS/NC deployments. NSFS/NC deployments have separate account management code in src/manage_nsfs/ directory. Therefore, account_server.js only processes accounts from account_schema.js where owner is an objectid reference, never from nsfs_account_schema.js where owner is a string.
Applied to files:
src/server/common_services/auth_server.js
🧬 Code graph analysis (1)
src/server/common_services/auth_server.js (2)
src/endpoint/s3/s3_rest.js (5)
account(256-256)account(344-344)bucket(406-406)bucket(428-428)is_owner(273-286)src/endpoint/s3/s3_bucket_policy_utils.js (1)
account(293-293)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: run-package-lock-validation
- GitHub Check: run-jest-unit-tests
- GitHub Check: Build Noobaa Image
Describe the Problem
In case there is no bucket policy, we want users under the account to be authorized to perform S3 operations.
Explain the Changes
Issues:
List of GAPs:
Testing Instructions:
Note:
nbis an alias that runs the local operator frombuild/_output/bin(alias created bydevenv).kubectl wait --for=condition=available backingstore/noobaa-default-backing-store --timeout=6m -n test1kubectl port-forward -n test1 service/s3 12443:443kubectl port-forward -n test1 service/iam 14443:443nb status --show-secrets -n test1and then:alias admin-s3='AWS_ACCESS_KEY=<access-key> AWS_SECRET_ACCESS_KEY=<secret-key> aws --no-verify-ssl --endpoint-url https://localhost:12443'alias admin-iam='AWS_ACCESS_KEY=<access-key> AWS_SECRET_ACCESS_KEY=<secret-key> aws --no-verify-ssl --endpoint-url https://localhost:14443'admin-iam iam list-users; echo $?first.bucket):admin-iam s3 ls; echo $?admin-iam iam create-user --user-name RobertNote: To validate user creation, you can rerun
admin-iam iam list-usersand expect 1 user in the listadmin-iam iam create-access-keys --user-name Robertuser-2-s3).echo 'test_data' | user-2-s3 s3 cp - s3://first.bucket/test_object.txt(should work).has_bucket_action_permissionfunction that was created in theauth_server):user-1-s3 s3 ls s3://first.bucketCode changes for testing:
src/sdk/object_sdk.jsuses cache expiry of 1 millisecond.const account_cache = new LRUCache({ name: 'AccountCache', - expiry_ms: config.OBJECT_SDK_ACCOUNT_CACHE_EXPIRY_MS, + expiry_ms: 1, //SDSDNotes:
In step 1 - deploying the system, I used
--use-standalone-dbfor simplicity (fewer steps for the system in Ready status).I used the admin account, but for IAM operations, there is no difference between a created account and an admin account. I tested with the admin only because it saves steps (I have the admin account upon system creation and a bucket).
Doc added/updated
Tests added
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.