@happyvertical/directory 0.76.2 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT.md +1 -1
- package/dist/adapters/aws.d.ts +14 -1
- package/dist/adapters/aws.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +304 -24
- package/dist/index.js.map +1 -1
- package/dist/shared/types.d.ts +63 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/metadata.json +1 -0
- package/package.json +3 -2
package/AGENT.md
CHANGED
|
@@ -28,7 +28,7 @@ pnpm --filter @happyvertical/directory clean
|
|
|
28
28
|
## Ecosystem Relationships
|
|
29
29
|
- Provides: Unified directory services with adapter-based architecture (Kanidm, Stalwart, PostgreSQL, AWS)
|
|
30
30
|
- Implements: none
|
|
31
|
-
- Requires: @happyvertical/utils, @aws-sdk/client-iam, @aws-sdk/client-organizations, pg
|
|
31
|
+
- Requires: @happyvertical/utils, @aws-sdk/client-iam, @aws-sdk/client-organizations, @aws-sdk/client-sts, pg
|
|
32
32
|
- Stability: stable (Primary package surface is described as implemented and production-oriented.)
|
|
33
33
|
<!-- END AGENT:GENERATED -->
|
|
34
34
|
|
package/dist/adapters/aws.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { AwsAccessKey, AwsAccount, AwsAccountCreationStatus, AwsDirectoryAdapter, AwsIamUser, AwsOptions, AwsOrganizationalUnit, CreateAwsAccountInput, CreateAwsIamUserInput, CreateAwsOuInput, CreateGroupInput, CreateUserInput, DirectoryGroup, DirectoryUser, UpdateGroupInput, UpdateUserInput } from '../shared/types.js';
|
|
1
|
+
import { AwsAccessKey, AwsAccount, AwsAccountCreationStatus, AwsAccountCreationWaitOptions, AwsAccountParent, AwsAssumeRoleInput, AwsDirectoryAdapter, AwsIamRole, AwsIamUser, AwsOptions, AwsOrganizationalUnit, AwsTemporaryCredentials, CreateAwsAccountInput, CreateAwsIamUserInput, CreateAwsOuInput, CreateGroupInput, CreateUserInput, DirectoryGroup, DirectoryUser, EnsureAwsAccountInput, EnsureAwsIamRoleInput, EnsureAwsOuInput, PutAwsIamRolePolicyInput, UpdateGroupInput, UpdateUserInput } from '../shared/types.js';
|
|
2
2
|
export declare class AwsAdapter implements AwsDirectoryAdapter {
|
|
3
3
|
readonly options: AwsOptions;
|
|
4
4
|
private readonly orgs;
|
|
5
5
|
private readonly iam;
|
|
6
|
+
private readonly sts;
|
|
6
7
|
constructor(options: AwsOptions);
|
|
7
8
|
testConnection(): Promise<boolean>;
|
|
8
9
|
disconnect(): Promise<void>;
|
|
@@ -23,10 +24,22 @@ export declare class AwsAdapter implements AwsDirectoryAdapter {
|
|
|
23
24
|
createOrganizationalUnit(input: CreateAwsOuInput): Promise<AwsOrganizationalUnit>;
|
|
24
25
|
getOrganizationalUnit(id: string): Promise<AwsOrganizationalUnit>;
|
|
25
26
|
listOrganizationalUnits(parentId: string): Promise<AwsOrganizationalUnit[]>;
|
|
27
|
+
findOrganizationalUnitByName(parentId: string, name: string): Promise<AwsOrganizationalUnit | null>;
|
|
28
|
+
ensureOrganizationalUnit(input: EnsureAwsOuInput): Promise<AwsOrganizationalUnit>;
|
|
26
29
|
createAccount(input: CreateAwsAccountInput): Promise<AwsAccountCreationStatus>;
|
|
27
30
|
getAccountCreationStatus(id: string): Promise<AwsAccountCreationStatus>;
|
|
28
31
|
listAccounts(): Promise<AwsAccount[]>;
|
|
32
|
+
findAccountByEmail(email: string): Promise<AwsAccount | null>;
|
|
33
|
+
ensureAccount(input: EnsureAwsAccountInput): Promise<AwsAccount>;
|
|
34
|
+
waitForAccountCreation(id: string, options?: AwsAccountCreationWaitOptions): Promise<AwsAccountCreationStatus>;
|
|
35
|
+
getAccountParent(accountId: string): Promise<AwsAccountParent | null>;
|
|
36
|
+
ensureAccountInOrganizationalUnit(accountId: string, destinationParentId: string): Promise<void>;
|
|
29
37
|
moveAccount(accountId: string, sourceParentId: string, destParentId: string): Promise<void>;
|
|
38
|
+
tagAwsOrganizationsResource(resourceId: string, tags: Record<string, string>): Promise<void>;
|
|
39
|
+
assumeAwsRole(input: AwsAssumeRoleInput): Promise<AwsTemporaryCredentials>;
|
|
40
|
+
getIamRole(roleName: string): Promise<AwsIamRole>;
|
|
41
|
+
ensureIamRole(input: EnsureAwsIamRoleInput): Promise<AwsIamRole>;
|
|
42
|
+
putIamRolePolicy(input: PutAwsIamRolePolicyInput): Promise<void>;
|
|
30
43
|
createIamUser(input: CreateAwsIamUserInput): Promise<AwsIamUser>;
|
|
31
44
|
getIamUser(username: string): Promise<AwsIamUser>;
|
|
32
45
|
deleteIamUser(username: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.d.ts","sourceRoot":"","sources":["../../src/adapters/aws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"aws.d.ts","sourceRoot":"","sources":["../../src/adapters/aws.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export { PostgresAdapter } from './adapters/postgres.js';
|
|
|
10
10
|
export { StalwartAdapter } from './adapters/stalwart.js';
|
|
11
11
|
export { AuthenticationError, ConflictError, ConnectionError, DirectoryError, NotFoundError, RateLimitError, ValidationError, } from './shared/errors.js';
|
|
12
12
|
export { getAwsAdapter, getDirectoryAdapter, getKanidmAdapter, getPostgresAdapter, getStalwartAdapter, isAwsOptions, isKanidmOptions, isPostgresOptions, isStalwartOptions, } from './shared/factory.js';
|
|
13
|
-
export type { AwsAccessKey, AwsAccount, AwsAccountCreationStatus, AwsDirectoryAdapter, AwsIamUser, AwsOptions, AwsOrganizationalUnit, CreateAwsAccountInput, CreateAwsIamUserInput, CreateAwsOuInput, CreateDkimKeyInput, CreateGroupInput, CreateMailboxInput, CreateMailDomainInput, CreateOAuth2ClientInput, CreatePgDatabaseInput, CreatePgRoleInput, CreateUserInput, CredentialResetIntent, DirectoryAdapter, DirectoryAdapterType, DirectoryGroup, DirectoryOrchestrator, DirectoryUser, DkimKey, DnsRecord, GetDirectoryAdapterOptions, KanidmDirectoryAdapter, KanidmOptions, Mailbox, MailDomain, OAuth2Client, PgDatabase, PgRole, PostgresDirectoryAdapter, PostgresOptions, StalwartDirectoryAdapter, StalwartOptions, TenantProvisioningInput, TenantProvisioningResult, UpdateGroupInput, UpdateMailboxInput, UpdateOAuth2ClientInput, UpdateUserInput, } from './shared/types.js';
|
|
13
|
+
export type { AwsAccessKey, AwsAccount, AwsAccountCreationStatus, AwsAccountCreationWaitOptions, AwsAccountParent, AwsAssumeRoleInput, AwsDirectoryAdapter, AwsIamRole, AwsIamUser, AwsOptions, AwsOrganizationalUnit, AwsTemporaryCredentials, CreateAwsAccountInput, CreateAwsIamUserInput, CreateAwsOuInput, CreateDkimKeyInput, CreateGroupInput, CreateMailboxInput, CreateMailDomainInput, CreateOAuth2ClientInput, CreatePgDatabaseInput, CreatePgRoleInput, CreateUserInput, CredentialResetIntent, DirectoryAdapter, DirectoryAdapterType, DirectoryGroup, DirectoryOrchestrator, DirectoryUser, DkimKey, DnsRecord, EnsureAwsAccountInput, EnsureAwsIamRoleInput, EnsureAwsOuInput, GetDirectoryAdapterOptions, KanidmDirectoryAdapter, KanidmOptions, Mailbox, MailDomain, OAuth2Client, PgDatabase, PgRole, PostgresDirectoryAdapter, PostgresOptions, PutAwsIamRolePolicyInput, StalwartDirectoryAdapter, StalwartOptions, TenantProvisioningInput, TenantProvisioningResult, UpdateGroupInput, UpdateMailboxInput, UpdateOAuth2ClientInput, UpdateUserInput, } from './shared/types.js';
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAG7B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,wBAAwB,EACxB,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,OAAO,EACP,SAAS,EACT,0BAA0B,EAC1B,sBAAsB,EACtB,aAAa,EACb,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,MAAM,EACN,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAG7B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,wBAAwB,EACxB,6BAA6B,EAC7B,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,UAAU,EACV,UAAU,EACV,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,0BAA0B,EAC1B,sBAAsB,EACtB,aAAa,EACb,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,MAAM,EACN,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,wBAAwB,EACxB,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { IAMClient, ListUsersCommand, CreateUserCommand, GetUserCommand, UpdateUserCommand, DeleteUserCommand, CreateGroupCommand, GetGroupCommand, DeleteGroupCommand, ListGroupsCommand, AddUserToGroupCommand, RemoveUserFromGroupCommand, ListGroupsForUserCommand, AttachUserPolicyCommand, DetachUserPolicyCommand, CreateAccessKeyCommand, DeleteAccessKeyCommand } from "@aws-sdk/client-iam";
|
|
2
|
-
import { OrganizationsClient, CreateOrganizationalUnitCommand, DescribeOrganizationalUnitCommand, ListOrganizationalUnitsForParentCommand, CreateAccountCommand, DescribeCreateAccountStatusCommand, ListAccountsCommand, MoveAccountCommand } from "@aws-sdk/client-organizations";
|
|
1
|
+
import { IAMClient, ListUsersCommand, CreateUserCommand, GetUserCommand, UpdateUserCommand, DeleteUserCommand, CreateGroupCommand, GetGroupCommand, DeleteGroupCommand, ListGroupsCommand, AddUserToGroupCommand, RemoveUserFromGroupCommand, ListGroupsForUserCommand, GetRoleCommand, UpdateAssumeRolePolicyCommand, UpdateRoleCommand, TagRoleCommand, CreateRoleCommand, PutRolePolicyCommand, AttachUserPolicyCommand, DetachUserPolicyCommand, CreateAccessKeyCommand, DeleteAccessKeyCommand } from "@aws-sdk/client-iam";
|
|
2
|
+
import { OrganizationsClient, CreateOrganizationalUnitCommand, DescribeOrganizationalUnitCommand, ListOrganizationalUnitsForParentCommand, CreateAccountCommand, DescribeCreateAccountStatusCommand, ListAccountsCommand, ListParentsCommand, MoveAccountCommand, TagResourceCommand } from "@aws-sdk/client-organizations";
|
|
3
|
+
import { STSClient, AssumeRoleCommand } from "@aws-sdk/client-sts";
|
|
3
4
|
import pg from "pg";
|
|
4
5
|
class DirectoryError extends Error {
|
|
5
6
|
code;
|
|
@@ -73,6 +74,8 @@ class RateLimitError extends DirectoryError {
|
|
|
73
74
|
this.retryAfter = retryAfter;
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
const DEFAULT_ACCOUNT_CREATION_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
78
|
+
const DEFAULT_ACCOUNT_CREATION_POLL_INTERVAL_MS = 5 * 1e3;
|
|
76
79
|
function handleAwsError(error, context) {
|
|
77
80
|
if (error instanceof AuthenticationError || error instanceof ConnectionError || error instanceof NotFoundError || error instanceof ConflictError || error instanceof DirectoryError) {
|
|
78
81
|
throw error;
|
|
@@ -137,6 +140,35 @@ function mapIamUserToAwsIamUser(user) {
|
|
|
137
140
|
createDate: user.CreateDate
|
|
138
141
|
};
|
|
139
142
|
}
|
|
143
|
+
function mapAwsAccount(account) {
|
|
144
|
+
return {
|
|
145
|
+
id: account.Id ?? "",
|
|
146
|
+
name: account.Name ?? "",
|
|
147
|
+
email: account.Email ?? "",
|
|
148
|
+
arn: account.Arn,
|
|
149
|
+
status: account.Status ? String(account.Status) : void 0
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function mapAwsIamRole(role) {
|
|
153
|
+
return {
|
|
154
|
+
roleName: role.RoleName ?? "",
|
|
155
|
+
arn: role.Arn,
|
|
156
|
+
roleId: role.RoleId,
|
|
157
|
+
path: role.Path,
|
|
158
|
+
createDate: role.CreateDate,
|
|
159
|
+
assumeRolePolicyDocument: role.AssumeRolePolicyDocument
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function toAwsTags(tags) {
|
|
163
|
+
const entries = Object.entries(tags ?? {}).filter(([key]) => key.length > 0);
|
|
164
|
+
if (entries.length === 0) {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
return entries.map(([Key, Value]) => ({ Key, Value }));
|
|
168
|
+
}
|
|
169
|
+
function sleep(ms) {
|
|
170
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
171
|
+
}
|
|
140
172
|
class AwsAdapter {
|
|
141
173
|
constructor(options) {
|
|
142
174
|
this.options = options;
|
|
@@ -146,9 +178,11 @@ class AwsAdapter {
|
|
|
146
178
|
};
|
|
147
179
|
this.orgs = new OrganizationsClient(clientConfig);
|
|
148
180
|
this.iam = new IAMClient(clientConfig);
|
|
181
|
+
this.sts = new STSClient(clientConfig);
|
|
149
182
|
}
|
|
150
183
|
orgs;
|
|
151
184
|
iam;
|
|
185
|
+
sts;
|
|
152
186
|
// ==========================================================================
|
|
153
187
|
// Connection
|
|
154
188
|
// ==========================================================================
|
|
@@ -323,7 +357,8 @@ class AwsAdapter {
|
|
|
323
357
|
const result = await this.orgs.send(
|
|
324
358
|
new CreateOrganizationalUnitCommand({
|
|
325
359
|
ParentId: input.parentId,
|
|
326
|
-
Name: input.name
|
|
360
|
+
Name: input.name,
|
|
361
|
+
Tags: toAwsTags(input.tags)
|
|
327
362
|
})
|
|
328
363
|
);
|
|
329
364
|
const ou = result.OrganizationalUnit;
|
|
@@ -356,21 +391,47 @@ class AwsAdapter {
|
|
|
356
391
|
}
|
|
357
392
|
async listOrganizationalUnits(parentId) {
|
|
358
393
|
try {
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
394
|
+
const organizationalUnits = [];
|
|
395
|
+
let nextToken;
|
|
396
|
+
do {
|
|
397
|
+
const result = await this.orgs.send(
|
|
398
|
+
new ListOrganizationalUnitsForParentCommand({
|
|
399
|
+
ParentId: parentId,
|
|
400
|
+
NextToken: nextToken
|
|
401
|
+
})
|
|
402
|
+
);
|
|
403
|
+
organizationalUnits.push(
|
|
404
|
+
...(result.OrganizationalUnits ?? []).map((ou) => ({
|
|
405
|
+
id: ou.Id ?? "",
|
|
406
|
+
name: ou.Name ?? "",
|
|
407
|
+
arn: ou.Arn,
|
|
408
|
+
parentId
|
|
409
|
+
}))
|
|
410
|
+
);
|
|
411
|
+
nextToken = result.NextToken;
|
|
412
|
+
} while (nextToken);
|
|
413
|
+
return organizationalUnits;
|
|
370
414
|
} catch (error) {
|
|
371
415
|
handleAwsError(error, `listOrganizationalUnits(${parentId})`);
|
|
372
416
|
}
|
|
373
417
|
}
|
|
418
|
+
async findOrganizationalUnitByName(parentId, name) {
|
|
419
|
+
const organizationalUnits = await this.listOrganizationalUnits(parentId);
|
|
420
|
+
return organizationalUnits.find((ou) => ou.name === name) ?? null;
|
|
421
|
+
}
|
|
422
|
+
async ensureOrganizationalUnit(input) {
|
|
423
|
+
const existing = await this.findOrganizationalUnitByName(
|
|
424
|
+
input.parentId,
|
|
425
|
+
input.name
|
|
426
|
+
);
|
|
427
|
+
if (existing) {
|
|
428
|
+
if (input.tags) {
|
|
429
|
+
await this.tagAwsOrganizationsResource(existing.id, input.tags);
|
|
430
|
+
}
|
|
431
|
+
return existing;
|
|
432
|
+
}
|
|
433
|
+
return this.createOrganizationalUnit(input);
|
|
434
|
+
}
|
|
374
435
|
// ==========================================================================
|
|
375
436
|
// Accounts (AwsDirectoryAdapter)
|
|
376
437
|
// ==========================================================================
|
|
@@ -380,12 +441,20 @@ class AwsAdapter {
|
|
|
380
441
|
new CreateAccountCommand({
|
|
381
442
|
AccountName: input.name,
|
|
382
443
|
Email: input.email,
|
|
383
|
-
...input.roleName ? { RoleName: input.roleName } : {}
|
|
444
|
+
...input.roleName ? { RoleName: input.roleName } : {},
|
|
445
|
+
Tags: toAwsTags(input.tags)
|
|
384
446
|
})
|
|
385
447
|
);
|
|
386
448
|
const status = result.CreateAccountStatus;
|
|
449
|
+
if (!status?.Id) {
|
|
450
|
+
throw new DirectoryError(
|
|
451
|
+
`createAccount(${input.name}) did not return a create account request id`,
|
|
452
|
+
"AWS_ACCOUNT_CREATION_REQUEST_ID_MISSING",
|
|
453
|
+
"aws"
|
|
454
|
+
);
|
|
455
|
+
}
|
|
387
456
|
return {
|
|
388
|
-
id: status
|
|
457
|
+
id: status.Id,
|
|
389
458
|
accountId: status?.AccountId,
|
|
390
459
|
state: status?.State ?? "IN_PROGRESS",
|
|
391
460
|
failureReason: status?.FailureReason ? String(status.FailureReason) : void 0
|
|
@@ -414,18 +483,107 @@ class AwsAdapter {
|
|
|
414
483
|
}
|
|
415
484
|
async listAccounts() {
|
|
416
485
|
try {
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
486
|
+
const accounts = [];
|
|
487
|
+
let nextToken;
|
|
488
|
+
do {
|
|
489
|
+
const result = await this.orgs.send(
|
|
490
|
+
new ListAccountsCommand({ NextToken: nextToken })
|
|
491
|
+
);
|
|
492
|
+
accounts.push(...(result.Accounts ?? []).map((a) => mapAwsAccount(a)));
|
|
493
|
+
nextToken = result.NextToken;
|
|
494
|
+
} while (nextToken);
|
|
495
|
+
return accounts;
|
|
425
496
|
} catch (error) {
|
|
426
497
|
handleAwsError(error, "listAccounts");
|
|
427
498
|
}
|
|
428
499
|
}
|
|
500
|
+
async findAccountByEmail(email) {
|
|
501
|
+
const accounts = await this.listAccounts();
|
|
502
|
+
return accounts.find(
|
|
503
|
+
(account) => account.email.toLowerCase() === email.toLowerCase()
|
|
504
|
+
) ?? null;
|
|
505
|
+
}
|
|
506
|
+
async ensureAccount(input) {
|
|
507
|
+
const existing = await this.findAccountByEmail(input.email);
|
|
508
|
+
if (existing) {
|
|
509
|
+
if (input.tags) {
|
|
510
|
+
await this.tagAwsOrganizationsResource(existing.id, input.tags);
|
|
511
|
+
}
|
|
512
|
+
return existing;
|
|
513
|
+
}
|
|
514
|
+
const createStatus = await this.createAccount(input);
|
|
515
|
+
const finalStatus = await this.waitForAccountCreation(
|
|
516
|
+
createStatus.id,
|
|
517
|
+
input.wait
|
|
518
|
+
);
|
|
519
|
+
if (finalStatus.state !== "SUCCEEDED" || !finalStatus.accountId) {
|
|
520
|
+
throw new DirectoryError(
|
|
521
|
+
`ensureAccount(${input.email}) failed: ${finalStatus.failureReason ?? finalStatus.state}`,
|
|
522
|
+
"AWS_ACCOUNT_CREATION_FAILED",
|
|
523
|
+
"aws"
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
const created = await this.findAccountByEmail(input.email);
|
|
527
|
+
if (created) {
|
|
528
|
+
return created;
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
id: finalStatus.accountId,
|
|
532
|
+
name: input.name,
|
|
533
|
+
email: input.email,
|
|
534
|
+
status: "ACTIVE"
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
async waitForAccountCreation(id, options = {}) {
|
|
538
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_ACCOUNT_CREATION_TIMEOUT_MS;
|
|
539
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_ACCOUNT_CREATION_POLL_INTERVAL_MS;
|
|
540
|
+
const startedAt = Date.now();
|
|
541
|
+
while (true) {
|
|
542
|
+
const status = await this.getAccountCreationStatus(id);
|
|
543
|
+
if (status.state !== "IN_PROGRESS") {
|
|
544
|
+
return status;
|
|
545
|
+
}
|
|
546
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
547
|
+
throw new DirectoryError(
|
|
548
|
+
`waitForAccountCreation(${id}) timed out after ${timeoutMs}ms`,
|
|
549
|
+
"AWS_ACCOUNT_CREATION_TIMEOUT",
|
|
550
|
+
"aws"
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
await sleep(pollIntervalMs);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async getAccountParent(accountId) {
|
|
557
|
+
try {
|
|
558
|
+
const result = await this.orgs.send(
|
|
559
|
+
new ListParentsCommand({ ChildId: accountId })
|
|
560
|
+
);
|
|
561
|
+
const parent = result.Parents?.[0];
|
|
562
|
+
if (!parent?.Id) {
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
id: parent.Id,
|
|
567
|
+
type: parent.Type ? String(parent.Type) : ""
|
|
568
|
+
};
|
|
569
|
+
} catch (error) {
|
|
570
|
+
handleAwsError(error, `getAccountParent(${accountId})`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
async ensureAccountInOrganizationalUnit(accountId, destinationParentId) {
|
|
574
|
+
const currentParent = await this.getAccountParent(accountId);
|
|
575
|
+
if (currentParent?.id === destinationParentId) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (!currentParent?.id) {
|
|
579
|
+
throw new DirectoryError(
|
|
580
|
+
`ensureAccountInOrganizationalUnit(${accountId}) could not determine the current account parent`,
|
|
581
|
+
"AWS_ACCOUNT_PARENT_MISSING",
|
|
582
|
+
"aws"
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
await this.moveAccount(accountId, currentParent.id, destinationParentId);
|
|
586
|
+
}
|
|
429
587
|
async moveAccount(accountId, sourceParentId, destParentId) {
|
|
430
588
|
try {
|
|
431
589
|
await this.orgs.send(
|
|
@@ -442,6 +600,128 @@ class AwsAdapter {
|
|
|
442
600
|
);
|
|
443
601
|
}
|
|
444
602
|
}
|
|
603
|
+
async tagAwsOrganizationsResource(resourceId, tags) {
|
|
604
|
+
const awsTags = toAwsTags(tags);
|
|
605
|
+
if (!awsTags) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
try {
|
|
609
|
+
await this.orgs.send(
|
|
610
|
+
new TagResourceCommand({
|
|
611
|
+
ResourceId: resourceId,
|
|
612
|
+
Tags: awsTags
|
|
613
|
+
})
|
|
614
|
+
);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
handleAwsError(error, `tagAwsOrganizationsResource(${resourceId})`);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
// ==========================================================================
|
|
620
|
+
// STS (AwsDirectoryAdapter)
|
|
621
|
+
// ==========================================================================
|
|
622
|
+
async assumeAwsRole(input) {
|
|
623
|
+
try {
|
|
624
|
+
const result = await this.sts.send(
|
|
625
|
+
new AssumeRoleCommand({
|
|
626
|
+
RoleArn: input.roleArn,
|
|
627
|
+
RoleSessionName: input.sessionName,
|
|
628
|
+
...input.externalId ? { ExternalId: input.externalId } : {},
|
|
629
|
+
...input.durationSeconds ? { DurationSeconds: input.durationSeconds } : {}
|
|
630
|
+
})
|
|
631
|
+
);
|
|
632
|
+
const credentials = result.Credentials;
|
|
633
|
+
if (!credentials?.AccessKeyId || !credentials.SecretAccessKey || !credentials.SessionToken) {
|
|
634
|
+
throw new DirectoryError(
|
|
635
|
+
`assumeAwsRole(${input.roleArn}) returned incomplete credentials`,
|
|
636
|
+
"AWS_ASSUME_ROLE_INCOMPLETE_CREDENTIALS",
|
|
637
|
+
"aws"
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
accessKeyId: credentials.AccessKeyId,
|
|
642
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
643
|
+
sessionToken: credentials.SessionToken,
|
|
644
|
+
expiration: credentials.Expiration,
|
|
645
|
+
assumedRoleArn: result.AssumedRoleUser?.Arn,
|
|
646
|
+
assumedRoleId: result.AssumedRoleUser?.AssumedRoleId
|
|
647
|
+
};
|
|
648
|
+
} catch (error) {
|
|
649
|
+
handleAwsError(error, `assumeAwsRole(${input.roleArn})`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
// ==========================================================================
|
|
653
|
+
// IAM Roles (AwsDirectoryAdapter)
|
|
654
|
+
// ==========================================================================
|
|
655
|
+
async getIamRole(roleName) {
|
|
656
|
+
try {
|
|
657
|
+
const result = await this.iam.send(
|
|
658
|
+
new GetRoleCommand({ RoleName: roleName })
|
|
659
|
+
);
|
|
660
|
+
return mapAwsIamRole(result.Role ?? {});
|
|
661
|
+
} catch (error) {
|
|
662
|
+
handleAwsError(error, `getIamRole(${roleName})`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
async ensureIamRole(input) {
|
|
666
|
+
try {
|
|
667
|
+
await this.getIamRole(input.roleName);
|
|
668
|
+
await this.iam.send(
|
|
669
|
+
new UpdateAssumeRolePolicyCommand({
|
|
670
|
+
RoleName: input.roleName,
|
|
671
|
+
PolicyDocument: input.assumeRolePolicyDocument
|
|
672
|
+
})
|
|
673
|
+
);
|
|
674
|
+
if (input.description !== void 0) {
|
|
675
|
+
await this.iam.send(
|
|
676
|
+
new UpdateRoleCommand({
|
|
677
|
+
RoleName: input.roleName,
|
|
678
|
+
Description: input.description
|
|
679
|
+
})
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
const tags = toAwsTags(input.tags);
|
|
683
|
+
if (tags) {
|
|
684
|
+
await this.iam.send(
|
|
685
|
+
new TagRoleCommand({
|
|
686
|
+
RoleName: input.roleName,
|
|
687
|
+
Tags: tags
|
|
688
|
+
})
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
return this.getIamRole(input.roleName);
|
|
692
|
+
} catch (error) {
|
|
693
|
+
if (!(error instanceof NotFoundError)) {
|
|
694
|
+
throw error;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
try {
|
|
698
|
+
const result = await this.iam.send(
|
|
699
|
+
new CreateRoleCommand({
|
|
700
|
+
RoleName: input.roleName,
|
|
701
|
+
AssumeRolePolicyDocument: input.assumeRolePolicyDocument,
|
|
702
|
+
...input.description ? { Description: input.description } : {},
|
|
703
|
+
...input.path ? { Path: input.path } : {},
|
|
704
|
+
Tags: toAwsTags(input.tags)
|
|
705
|
+
})
|
|
706
|
+
);
|
|
707
|
+
return mapAwsIamRole(result.Role ?? {});
|
|
708
|
+
} catch (error) {
|
|
709
|
+
handleAwsError(error, `ensureIamRole(${input.roleName})`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
async putIamRolePolicy(input) {
|
|
713
|
+
try {
|
|
714
|
+
await this.iam.send(
|
|
715
|
+
new PutRolePolicyCommand({
|
|
716
|
+
RoleName: input.roleName,
|
|
717
|
+
PolicyName: input.policyName,
|
|
718
|
+
PolicyDocument: input.policyDocument
|
|
719
|
+
})
|
|
720
|
+
);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
handleAwsError(error, `putIamRolePolicy(${input.roleName})`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
445
725
|
// ==========================================================================
|
|
446
726
|
// IAM Users (AwsDirectoryAdapter)
|
|
447
727
|
// ==========================================================================
|