Skip to content

Commit ad1e403

Browse files
Sakshi MunjalSakshi Munjal
authored andcommitted
add ldap changes
Signed-off-by: Sakshi Munjal <sakshimunjal@Sakshis-MacBook-Pro.local>
1 parent b7bd233 commit ad1e403

15 files changed

Lines changed: 384 additions & 34 deletions

File tree

docs/NooBaaNonContainerized/ldap_non_containerised.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ sudo node src/cmd/manage_nsfs.js account add \
203203
--new_buckets_path /private/tmp/noobaa-buckets
204204
```
205205

206-
2. Create a role with a Federated trust policy. `Principal.Federated` must match the LDAP URI in `ldap_config` (scheme is stripped when matching). Optional `Condition` blocks restrict by LDAP attributes such as `ou` or `memberOf`:
206+
2. Create a role with a Federated trust policy. `Principal.Federated` must be arn:aws:iam:::ldap-provider/<host>[:port]; host:port must match ldap_config.uri after :// (scheme is stripped when matching). Optional `Condition` blocks restrict by LDAP attributes such as `ou` or `memberOf`:
207207

208208
```bash
209209
export OWNER_ACCESS_KEY=<owner-access-key>
@@ -215,7 +215,7 @@ cat > /tmp/ldap-trust-policy.json <<'EOF'
215215
"Version": "2012-10-17",
216216
"Statement": [{
217217
"Effect": "Allow",
218-
"Principal": { "Federated": "ldaps://127.0.0.1:1636" },
218+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
219219
"Action": "sts:AssumeRoleWithWebIdentity"
220220
}]
221221
}
@@ -437,7 +437,7 @@ ldapsearch -H "$LDAP_URI" -x \
437437
| Symptom | Check |
438438
| --- | --- |
439439
| `NO_SUCH_ROLE` | IAM role exists under the owner account (`CreateRole`); ARN owner id + role name match. For legacy: account has `role_config` and `role_name` matches. |
440-
| Access denied after LDAP bind | Trust policy `Principal.Federated` URI matches `ldap_config.uri` (scheme stripped). `Condition` (`ldap:ou` / `ldap:memberOf`) matches bind attributes. |
440+
| Access denied after LDAP bind | Trust policy `Principal.Federated` ARN matches `ldap_config.uri` (scheme stripped). `Condition` (`ldap:ou` / `ldap:memberOf`) matches bind attributes. |
441441
| `issue with LDAP authentication` | Wrong username/password; check `search_dn` and `dn_attribute` |
442442

443443
```bash

docs/design/iam_nc.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,13 @@ Used when an external identity provider (LDAP etc.) authenticates the user. NooB
342342
"Version": "2012-10-17",
343343
"Statement": [{
344344
"Effect": "Allow",
345-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
345+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
346346
"Action": "sts:AssumeRoleWithWebIdentity"
347347
}]
348348
}
349349
```
350350

351-
The `Federated` value must match the LDAP server URI in `/etc/noobaa-server/ldap_config`. Matching strips the `ldap://` / `ldaps://` prefix.
351+
The `Federated` value must be arn:aws:iam:::ldap-provider/<host>[:port] and host:port must match the LDAP server URI in `/etc/noobaa-server/ldap_config`. Matching strips the `ldap://` / `ldaps://` prefix.
352352

353353
##### LDAP group / attribute conditions
354354

@@ -366,7 +366,7 @@ Condition keys use the `ldap:<attribute>` format. NooBaa strips the `ldap:` pref
366366
"Version": "2012-10-17",
367367
"Statement": [{
368368
"Effect": "Allow",
369-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
369+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
370370
"Action": "sts:AssumeRoleWithWebIdentity",
371371
"Condition": {
372372
"StringEquals": { "ldap:ou": "Delivering Crew" }
@@ -382,7 +382,7 @@ Condition keys use the `ldap:<attribute>` format. NooBaa strips the `ldap:` pref
382382
"Version": "2012-10-17",
383383
"Statement": [{
384384
"Effect": "Allow",
385-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
385+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
386386
"Action": "sts:AssumeRoleWithWebIdentity",
387387
"Condition": {
388388
"ForAnyValue:StringEquals": {
@@ -403,7 +403,7 @@ Condition keys use the `ldap:<attribute>` format. NooBaa strips the `ldap:` pref
403403
"Version": "2012-10-17",
404404
"Statement": [{
405405
"Effect": "Allow",
406-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
406+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
407407
"Action": "sts:AssumeRoleWithWebIdentity",
408408
"Condition": {
409409
"StringEquals": { "ldap:ou": "Delivering Crew" },
@@ -423,15 +423,15 @@ Condition keys use the `ldap:<attribute>` format. NooBaa strips the `ldap:` pref
423423
"Statement": [
424424
{
425425
"Effect": "Allow",
426-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
426+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
427427
"Action": "sts:AssumeRoleWithWebIdentity",
428428
"Condition": {
429429
"StringEquals": { "ldap:ou": "Delivering Crew" }
430430
}
431431
},
432432
{
433433
"Effect": "Allow",
434-
"Principal": { "Federated": "ldap://127.0.0.1:1389" },
434+
"Principal": { "Federated": "arn:aws:iam:::ldap-provider/127.0.0.1:1636" },
435435
"Action": "sts:AssumeRoleWithWebIdentity",
436436
"Condition": {
437437
"ForAnyValue:StringEquals": {
@@ -492,7 +492,7 @@ NooBaa STS
492492
│ └─ look up role entity via config_fs / AccountSpaceFS
493493
│ [Phase 2: look up standalone role entity by owner_id, role_name]
494494
├─► 5. [TODO] Evaluate trust policy
495-
│ ├─ Principal fit (Federated URI match / "*" / AWS ARN)
495+
│ ├─ Principal fit (Federated ldap-provider ARN match / "*" / AWS ARN)
496496
│ ├─ Action fit (sts:AssumeRoleWithWebIdentity)
497497
│ └─ Condition fit (e.g. ldap:ou == "Engineering")
498498
└─► 6. Issue temporary credentials (AccessKeyId + SecretAccessKey + SessionToken)
@@ -599,7 +599,7 @@ Phase 2 — append `iam_role_policies`:
599599
### Code Changes
600600
601601
1. Implement all role CRUD methods in `src/sdk/accountspace_fs.js` and `config_fs.js`
602-
2. Add support for `Principal.Federated` in trust-policy evaluation (`_is_principal_fit()` / access policy utils) — LDAP URI match and OIDC/`iss` match
602+
2. Add support for `Principal.Federated` in trust-policy evaluation (`_is_principal_fit()` / access policy utils) — LDAP ARN match and OIDC/`iss` match
603603
3. Load `assume_role_policy_document` from role entity via `config_fs` / **role cache** (same pattern as account cache)
604604
4. Implement LDAP and Keycloak condition evaluation for trust policy (`_is_identity_condition_fit`) — including `ldap:ou` / `ldap:memberOf`
605605
5. Schema changes for roles (`name`, `owner`, `assume_role_policy_document`, …)

src/api/common_api.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ module.exports = {
117117
enum: ['DISABLED', 'SUSPENDED', 'ENABLED']
118118
},
119119

120+
identity_type: {
121+
type: 'string',
122+
enum: ['ACCOUNT', 'USER', 'ROLE']
123+
},
124+
120125
assume_role_policy: {
121126
type: 'object',
122127
required: ['statement'],

src/endpoint/iam/iam_utils.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const s3_utils = require('../s3/s3_utils');
66
const { IamError } = require('./iam_errors');
77
const { AWS_IAM_PATH_REGEXP, AWS_IAM_LIST_MARKER, AWS_IAM_ACCESS_KEY_INPUT_REGEXP, AWS_POLICY_NAME_REGEXP,
88
AWS_POLICY_DOCUMENT_REGEXP, AWS_POLICY_SID_REGEXP, AWS_ROLE_NAME_REGEXP, AWS_ROLE_DESCRIPTION_REGEXP,
9-
AWS_OIDC_PROVIDER_ARN_REGEXP } = require('../../util/string_utils');
9+
AWS_OIDC_PROVIDER_ARN_REGEXP, AWS_LDAP_PROVIDER_ARN_REGEXP
10+
} = require('../../util/string_utils');
1011
const iam_constants = require('./iam_constants');
1112
const { RpcError } = require('../../rpc');
1213
const validation_utils = require('../../util/validation_utils');
@@ -1121,8 +1122,9 @@ function _validate_policy_document_iam_structure(policy_document) {
11211122
* Specifically:
11221123
* - Version must be '2012-10-17' or '2008-10-17'.
11231124
* - Statement must be a non-empty array.
1124-
* - Principal.Federated entries, when present, must conform to the OIDC-provider ARN format:
1125-
* eg: arn:aws:iam::<12-digit-account-id>:oidc-provider/<provider-url> or arn:aws:iam:::oidc-provider/<provider-url>
1125+
* - Principal.Federated entries, when present, must conform to the OIDC-provider or LDAP-provider ARN format:
1126+
* - OIDC ARN: arn:aws:iam::<12-digit-account-id>:oidc-provider/<provider-url> or arn:aws:iam:::oidc-provider/<provider-url>
1127+
* - LDAP ARN: arn:aws:iam::<account-id?>:ldap-provider/<host>[:port]
11261128
*
11271129
* @param {object} policy_document - parsed trust policy JSON
11281130
*/
@@ -1149,10 +1151,13 @@ function _validate_assume_role_policy_document_iam_structure(policy_document) {
11491151
if (federated !== undefined) {
11501152
const entries = Array.isArray(federated) ? federated : [federated];
11511153
for (const entry of entries) {
1152-
if (typeof entry !== 'string' || !AWS_OIDC_PROVIDER_ARN_REGEXP.test(entry)) {
1154+
const is_oidc = typeof entry === 'string' && AWS_OIDC_PROVIDER_ARN_REGEXP.test(entry);
1155+
const is_ldap = typeof entry === 'string' && AWS_LDAP_PROVIDER_ARN_REGEXP.test(entry);
1156+
if (!is_oidc && !is_ldap) {
11531157
throw_malformed_policy_document_error(
11541158
'Invalid Federated principal. ' +
1155-
'Expected format: arn:aws:iam::<12-digit-account-id>:oidc-provider/<provider-url>'
1159+
'Expected format: arn:aws:iam::<12-digit-account-id>:oidc-provider/<provider-url> ' +
1160+
'or arn:aws:iam::<account-id>:ldap-provider/<host>[:port] '
11561161
);
11571162
}
11581163
}

src/endpoint/sts/sts_rest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ async function authenticate_request(req) {
117117
signature_utils.authenticate_request_by_service(req, req.sts_sdk);
118118
if (req.op_name === 'post_assume_role_with_web_identity') {
119119
const web_identity_info = access_policy_utils.fetch_web_identity_info(req);
120-
const is_ldap_request = web_identity_info.username;
120+
const is_ldap_request = web_identity_info.type === 'ldap' || web_identity_info.user;
121121
if (is_ldap_request) {
122122
// fetch LDAP identity info
123123
req.sts_sdk.identity_info = await req.sts_sdk.authenticate_web_identity(req);

src/manage_nsfs/manage_nsfs_cli_errors.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ ManageCLIError.AccountDeleteForbiddenHasBuckets = Object.freeze({
245245
http_code: 403,
246246
});
247247

248-
ManageCLIError.AccountDeleteForbiddenHasIAMAccounts = Object.freeze({
249-
code: 'AccountDeleteForbiddenHasIAMAccounts',
250-
message: 'Cannot delete account that is owner of IAM accounts. ' +
251-
'You must delete all IAM accounts before deleting the root account',
248+
ManageCLIError.AccountDeleteForbiddenHasIAMUsers = Object.freeze({
249+
code: 'AccountDeleteForbiddenHasIAMUsers',
250+
message: 'Cannot delete account that is owner of IAM users. ' +
251+
'You must delete all IAM users before deleting the root account',
252252
http_code: 403,
253253
});
254254

@@ -598,7 +598,7 @@ const NSFS_CLI_ERROR_EVENT_MAP = {
598598
AccountAccessKeyAlreadyExists: NoobaaEvent.ACCOUNT_ALREADY_EXISTS,
599599
AccountNameAlreadyExists: NoobaaEvent.ACCOUNT_ALREADY_EXISTS,
600600
AccountDeleteForbiddenHasBuckets: NoobaaEvent.ACCOUNT_DELETE_FORBIDDEN,
601-
AccountDeleteForbiddenHasIAMAccounts: NoobaaEvent.ACCOUNT_DELETE_FORBIDDEN,
601+
AccountDeleteForbiddenHasIAMUsers: NoobaaEvent.ACCOUNT_DELETE_FORBIDDEN,
602602
AccountDeleteForbiddenHasIAMRoles: NoobaaEvent.ACCOUNT_DELETE_FORBIDDEN,
603603
BucketAlreadyExists: NoobaaEvent.BUCKET_ALREADY_EXISTS,
604604
BucketSetForbiddenBucketOwnerNotExists: NoobaaEvent.BUCKET_OWNER_NOT_EXISTS,

src/manage_nsfs/manage_nsfs_validations.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ async function validate_account_args(config_fs, data, action, is_flag_iam_operat
659659
*/
660660
async function validate_account_resources_before_deletion(config_fs, data) {
661661
await validate_account_not_owns_buckets(config_fs, data);
662-
// If it is root account (not owned by other account) then we check that it doesn't owns IAM accounts
662+
// If it is root account (not owned by other account) then we check that it doesn't owns IAM users
663663
if (data.owner === undefined) {
664664
await check_if_root_account_does_not_have_IAM_users(config_fs, data, ACTIONS.DELETE);
665665
await validate_account_not_owns_roles(config_fs, data);
@@ -739,7 +739,7 @@ async function check_if_root_account_does_not_have_IAM_users(config_fs, account_
739739
if (is_root_account_owns_user) {
740740
const detail_msg = `Account ${account_to_check.name} has IAM account ${account_data.name}`;
741741
if (action === ACTIONS.DELETE) {
742-
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasIAMAccounts, detail_msg);
742+
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasIAMUsers, detail_msg);
743743
}
744744
// else it is called with action ACTIONS.UPDATE
745745
throw_cli_error(ManageCLIError.AccountCannotBeRootAccountsManager, detail_msg);

src/sdk/accountspace_fs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ class AccountSpaceFS {
942942
_id: generate_id(),
943943
name: params.role_name,
944944
email: params.role_name,
945-
type: 'role',
945+
identity_type: 'ROLE',
946946
owner: requesting_account._id,
947947
iam_path: params.iam_path || IAM_DEFAULT_PATH,
948948
creation_date: new Date().toISOString(),

src/sdk/sts_sdk.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class StsSDK {
154154
* @param {Object} req - Request object
155155
*/
156156
async get_assumed_ldap_user(req) {
157-
const ldap_auth_result = await this.authenticate_web_identity(req);
157+
const ldap_auth_result = this.identity_info || await this.authenticate_web_identity(req);
158158
const role_config = await this._assume_role(req.body.role_arn);
159159
dbg.log0('sts_sdk.get_assumed_role_with_web_identity res', 'account.role_config: ', role_config);
160160
return {

src/server/system_services/schemas/nsfs_account_schema.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,9 @@ module.exports = {
126126
assume_role_policy_document: {
127127
$ref: 'common_api#/definitions/iam_trust_policy_document',
128128
},
129-
type: {
129+
identity_type: {
130130
// to make consistent with containerized
131-
type: 'string',
132-
enum: ['account', 'user', 'role'],
131+
$ref: 'common_api#/definitions/identity_type',
133132
}
134133
}
135134
};

0 commit comments

Comments
 (0)