@beesolve/aws-accounts 1.1.0 → 1.2.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/README.md +1 -1
- package/dist/applyLogic.js +239 -3
- package/dist/awsConfig.js +402 -23
- package/dist/cli.js +63 -26
- package/dist/commands/graveyard.js +27 -0
- package/dist/commands/remote.js +139 -38
- package/dist/commands/validate.js +45 -0
- package/dist/diff.js +255 -8
- package/dist/lambda/handler.js +8 -4
- package/dist/lambdaClient.js +5 -2
- package/dist/operations.js +83 -1
- package/dist/scanLogic.js +163 -7
- package/dist/state.js +162 -6
- package/dist-lambda/handler.mjs +647 -22
- package/dist-lambda/lambda.zip +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/applyLogic.js
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import { PutAccountNameCommand } from "@aws-sdk/client-account";
|
|
2
1
|
import {
|
|
2
|
+
DeleteAlternateContactCommand,
|
|
3
|
+
PutAccountNameCommand,
|
|
4
|
+
PutAlternateContactCommand
|
|
5
|
+
} from "@aws-sdk/client-account";
|
|
6
|
+
import {
|
|
7
|
+
AttachPolicyCommand,
|
|
3
8
|
CreateOrganizationalUnitCommand,
|
|
9
|
+
CreatePolicyCommand,
|
|
4
10
|
DeleteOrganizationalUnitCommand,
|
|
11
|
+
DeletePolicyCommand,
|
|
12
|
+
DetachPolicyCommand,
|
|
5
13
|
ListAccountsForParentCommand,
|
|
6
14
|
ListOrganizationalUnitsForParentCommand,
|
|
7
15
|
MoveAccountCommand,
|
|
8
16
|
TagResourceCommand,
|
|
9
17
|
UntagResourceCommand,
|
|
10
|
-
UpdateOrganizationalUnitCommand
|
|
18
|
+
UpdateOrganizationalUnitCommand,
|
|
19
|
+
UpdatePolicyCommand
|
|
11
20
|
} from "@aws-sdk/client-organizations";
|
|
12
21
|
import {
|
|
13
22
|
CreateGroupMembershipCommand,
|
|
@@ -35,6 +44,7 @@ import {
|
|
|
35
44
|
DetachManagedPolicyFromPermissionSetCommand,
|
|
36
45
|
ProvisionPermissionSetCommand,
|
|
37
46
|
PutInlinePolicyToPermissionSetCommand,
|
|
47
|
+
UpdateInstanceAccessControlAttributeConfigurationCommand,
|
|
38
48
|
UpdatePermissionSetCommand
|
|
39
49
|
} from "@aws-sdk/client-sso-admin";
|
|
40
50
|
import { createAccountAndMoveToOu } from "./accountCreation.js";
|
|
@@ -42,6 +52,7 @@ import { assertUnreachable, delay } from "./helpers.js";
|
|
|
42
52
|
import {
|
|
43
53
|
addGroupMembershipToWorkingState,
|
|
44
54
|
addAccountAssignmentToWorkingState,
|
|
55
|
+
addOrgPolicyAttachmentToWorkingState,
|
|
45
56
|
createGroupMembershipKey,
|
|
46
57
|
moveAccountInWorkingState,
|
|
47
58
|
removeAccountAssignmentFromWorkingState,
|
|
@@ -50,12 +61,15 @@ import {
|
|
|
50
61
|
removeIdcPermissionSetFromWorkingState,
|
|
51
62
|
removeIdcUserFromWorkingState,
|
|
52
63
|
removeOrganizationalUnitFromWorkingState,
|
|
64
|
+
removeOrgPolicyAttachmentFromWorkingState,
|
|
65
|
+
removeOrgPolicyFromWorkingState,
|
|
53
66
|
renameOrganizationalUnitInWorkingState,
|
|
54
67
|
upsertIdcGroupInWorkingState,
|
|
55
68
|
upsertIdcPermissionSetInWorkingState,
|
|
56
69
|
upsertIdcUserInWorkingState,
|
|
57
70
|
upsertAccountInWorkingState,
|
|
58
|
-
upsertOrganizationalUnitInWorkingState
|
|
71
|
+
upsertOrganizationalUnitInWorkingState,
|
|
72
|
+
upsertOrgPolicyInWorkingState
|
|
59
73
|
} from "./state.js";
|
|
60
74
|
async function executeOperation(props) {
|
|
61
75
|
const operation = props.operation;
|
|
@@ -909,6 +923,218 @@ async function executeOperation(props) {
|
|
|
909
923
|
}
|
|
910
924
|
});
|
|
911
925
|
}
|
|
926
|
+
if (operation.kind === "createOrgPolicy") {
|
|
927
|
+
props.logger.log(
|
|
928
|
+
`Creating org policy "${operation.policyName}" (${operation.policyType})...`
|
|
929
|
+
);
|
|
930
|
+
const response = await props.organizationsClient.send(
|
|
931
|
+
new CreatePolicyCommand({
|
|
932
|
+
Name: operation.policyName,
|
|
933
|
+
Description: operation.description.length > 0 ? operation.description : void 0,
|
|
934
|
+
Content: operation.content,
|
|
935
|
+
Type: operation.policyType
|
|
936
|
+
})
|
|
937
|
+
);
|
|
938
|
+
const policy = response.Policy?.PolicySummary;
|
|
939
|
+
if (policy?.Id == null || policy.Arn == null) {
|
|
940
|
+
throw new Error(
|
|
941
|
+
`CreatePolicy for "${operation.policyName}" returned incomplete data.`
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
props.logger.log(`Done: "${operation.policyName}"`);
|
|
945
|
+
return upsertOrgPolicyInWorkingState({
|
|
946
|
+
workingState: props.state,
|
|
947
|
+
policy: {
|
|
948
|
+
id: policy.Id,
|
|
949
|
+
arn: policy.Arn,
|
|
950
|
+
name: operation.policyName,
|
|
951
|
+
description: operation.description,
|
|
952
|
+
type: operation.policyType,
|
|
953
|
+
content: operation.content
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
if (operation.kind === "updateOrgPolicyContent") {
|
|
958
|
+
props.logger.log(`Updating org policy content "${operation.policyName}"...`);
|
|
959
|
+
await props.organizationsClient.send(
|
|
960
|
+
new UpdatePolicyCommand({
|
|
961
|
+
PolicyId: operation.policyId,
|
|
962
|
+
Content: operation.content
|
|
963
|
+
})
|
|
964
|
+
);
|
|
965
|
+
props.logger.log(`Done: "${operation.policyName}"`);
|
|
966
|
+
const currentPolicy = props.state.organization.policiesById[operation.policyId];
|
|
967
|
+
if (currentPolicy == null) {
|
|
968
|
+
return props.state;
|
|
969
|
+
}
|
|
970
|
+
return upsertOrgPolicyInWorkingState({
|
|
971
|
+
workingState: props.state,
|
|
972
|
+
policy: { ...currentPolicy, content: operation.content }
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
if (operation.kind === "updateOrgPolicyDescription") {
|
|
976
|
+
props.logger.log(
|
|
977
|
+
`Updating org policy description "${operation.policyName}"...`
|
|
978
|
+
);
|
|
979
|
+
await props.organizationsClient.send(
|
|
980
|
+
new UpdatePolicyCommand({
|
|
981
|
+
PolicyId: operation.policyId,
|
|
982
|
+
Description: operation.description
|
|
983
|
+
})
|
|
984
|
+
);
|
|
985
|
+
props.logger.log(`Done: "${operation.policyName}"`);
|
|
986
|
+
const currentPolicy = props.state.organization.policiesById[operation.policyId];
|
|
987
|
+
if (currentPolicy == null) {
|
|
988
|
+
return props.state;
|
|
989
|
+
}
|
|
990
|
+
return upsertOrgPolicyInWorkingState({
|
|
991
|
+
workingState: props.state,
|
|
992
|
+
policy: { ...currentPolicy, description: operation.description }
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
if (operation.kind === "attachOrgPolicy") {
|
|
996
|
+
props.logger.log(
|
|
997
|
+
`Attaching org policy "${operation.policyName}" to "${operation.targetName}"...`
|
|
998
|
+
);
|
|
999
|
+
const resolvedPolicyId = resolvePolicyId({
|
|
1000
|
+
state: props.state,
|
|
1001
|
+
policyId: operation.policyId,
|
|
1002
|
+
policyName: operation.policyName
|
|
1003
|
+
});
|
|
1004
|
+
await props.organizationsClient.send(
|
|
1005
|
+
new AttachPolicyCommand({
|
|
1006
|
+
PolicyId: resolvedPolicyId,
|
|
1007
|
+
TargetId: operation.targetId
|
|
1008
|
+
})
|
|
1009
|
+
);
|
|
1010
|
+
props.logger.log(`Done: "${operation.policyName}" -> "${operation.targetName}"`);
|
|
1011
|
+
const targetType = operation.targetId === props.context.organization.rootId ? "ROOT" : props.state.organization.organizationalUnitsById[operation.targetId] != null ? "ORGANIZATIONAL_UNIT" : "ACCOUNT";
|
|
1012
|
+
return addOrgPolicyAttachmentToWorkingState({
|
|
1013
|
+
workingState: props.state,
|
|
1014
|
+
attachment: {
|
|
1015
|
+
policyId: resolvedPolicyId,
|
|
1016
|
+
targetId: operation.targetId,
|
|
1017
|
+
targetType
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
if (operation.kind === "detachOrgPolicy") {
|
|
1022
|
+
props.logger.log(
|
|
1023
|
+
`Detaching org policy "${operation.policyName}" from "${operation.targetName}"...`
|
|
1024
|
+
);
|
|
1025
|
+
await props.organizationsClient.send(
|
|
1026
|
+
new DetachPolicyCommand({
|
|
1027
|
+
PolicyId: operation.policyId,
|
|
1028
|
+
TargetId: operation.targetId
|
|
1029
|
+
})
|
|
1030
|
+
);
|
|
1031
|
+
props.logger.log(`Done: "${operation.policyName}" x "${operation.targetName}"`);
|
|
1032
|
+
return removeOrgPolicyAttachmentFromWorkingState({
|
|
1033
|
+
workingState: props.state,
|
|
1034
|
+
policyId: operation.policyId,
|
|
1035
|
+
targetId: operation.targetId
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
if (operation.kind === "deleteOrgPolicy") {
|
|
1039
|
+
props.logger.log(`Deleting org policy "${operation.policyName}"...`);
|
|
1040
|
+
await props.organizationsClient.send(
|
|
1041
|
+
new DeletePolicyCommand({ PolicyId: operation.policyId })
|
|
1042
|
+
);
|
|
1043
|
+
props.logger.log(`Done: "${operation.policyName}"`);
|
|
1044
|
+
return removeOrgPolicyFromWorkingState({
|
|
1045
|
+
workingState: props.state,
|
|
1046
|
+
policyId: operation.policyId
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
if (operation.kind === "putAlternateContact") {
|
|
1050
|
+
props.logger.log(
|
|
1051
|
+
`Setting ${operation.contactType} alternate contact for "${operation.accountName}" (${operation.accountId})...`
|
|
1052
|
+
);
|
|
1053
|
+
await props.accountClient.send(
|
|
1054
|
+
new PutAlternateContactCommand({
|
|
1055
|
+
AccountId: operation.accountId,
|
|
1056
|
+
AlternateContactType: operation.contactType,
|
|
1057
|
+
Name: operation.name,
|
|
1058
|
+
EmailAddress: operation.email,
|
|
1059
|
+
PhoneNumber: operation.phone,
|
|
1060
|
+
Title: operation.title
|
|
1061
|
+
})
|
|
1062
|
+
);
|
|
1063
|
+
props.logger.log(`Done: ${operation.contactType} contact for "${operation.accountName}"`);
|
|
1064
|
+
const account = props.state.organization.accountsById[operation.accountId];
|
|
1065
|
+
if (account == null) {
|
|
1066
|
+
throw new Error(
|
|
1067
|
+
`Could not resolve account (${operation.accountId}) in working state.`
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
const updatedContacts = [
|
|
1071
|
+
...(account.alternateContacts ?? []).filter(
|
|
1072
|
+
(c) => c.contactType !== operation.contactType
|
|
1073
|
+
),
|
|
1074
|
+
{
|
|
1075
|
+
contactType: operation.contactType,
|
|
1076
|
+
name: operation.name,
|
|
1077
|
+
email: operation.email,
|
|
1078
|
+
phone: operation.phone,
|
|
1079
|
+
title: operation.title
|
|
1080
|
+
}
|
|
1081
|
+
];
|
|
1082
|
+
return upsertAccountInWorkingState({
|
|
1083
|
+
workingState: props.state,
|
|
1084
|
+
account: { ...account, alternateContacts: updatedContacts }
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
if (operation.kind === "deleteAlternateContact") {
|
|
1088
|
+
props.logger.log(
|
|
1089
|
+
`Deleting ${operation.contactType} alternate contact for "${operation.accountName}" (${operation.accountId})...`
|
|
1090
|
+
);
|
|
1091
|
+
await props.accountClient.send(
|
|
1092
|
+
new DeleteAlternateContactCommand({
|
|
1093
|
+
AccountId: operation.accountId,
|
|
1094
|
+
AlternateContactType: operation.contactType
|
|
1095
|
+
})
|
|
1096
|
+
);
|
|
1097
|
+
props.logger.log(`Done: removed ${operation.contactType} contact for "${operation.accountName}"`);
|
|
1098
|
+
const account = props.state.organization.accountsById[operation.accountId];
|
|
1099
|
+
if (account == null) {
|
|
1100
|
+
throw new Error(
|
|
1101
|
+
`Could not resolve account (${operation.accountId}) in working state.`
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
return upsertAccountInWorkingState({
|
|
1105
|
+
workingState: props.state,
|
|
1106
|
+
account: {
|
|
1107
|
+
...account,
|
|
1108
|
+
alternateContacts: (account.alternateContacts ?? []).filter(
|
|
1109
|
+
(c) => c.contactType !== operation.contactType
|
|
1110
|
+
)
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
if (operation.kind === "setIdcAccessControlAttributes") {
|
|
1115
|
+
props.logger.log(
|
|
1116
|
+
`Setting IdC access control attributes (${operation.attributes.length} attribute(s))...`
|
|
1117
|
+
);
|
|
1118
|
+
await props.ssoAdminClient.send(
|
|
1119
|
+
new UpdateInstanceAccessControlAttributeConfigurationCommand({
|
|
1120
|
+
InstanceArn: props.state.identityCenter.instanceArn,
|
|
1121
|
+
InstanceAccessControlAttributeConfiguration: {
|
|
1122
|
+
AccessControlAttributes: operation.attributes.map((attr) => ({
|
|
1123
|
+
Key: attr.key,
|
|
1124
|
+
Value: { Source: attr.source }
|
|
1125
|
+
}))
|
|
1126
|
+
}
|
|
1127
|
+
})
|
|
1128
|
+
);
|
|
1129
|
+
props.logger.log(`Done: access control attributes updated`);
|
|
1130
|
+
return {
|
|
1131
|
+
...props.state,
|
|
1132
|
+
identityCenter: {
|
|
1133
|
+
...props.state.identityCenter,
|
|
1134
|
+
accessControlAttributes: operation.attributes
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
912
1138
|
assertUnreachable(operation, "Unsupported operation kind in apply.");
|
|
913
1139
|
}
|
|
914
1140
|
function resolveAssignmentDependencies(props) {
|
|
@@ -969,6 +1195,16 @@ function resolveGroupByDisplayName(props) {
|
|
|
969
1195
|
}
|
|
970
1196
|
return group;
|
|
971
1197
|
}
|
|
1198
|
+
function resolvePolicyId(props) {
|
|
1199
|
+
if (props.policyId !== "__pending_creation__") return props.policyId;
|
|
1200
|
+
const policy = props.state.organization.policiesByName[props.policyName];
|
|
1201
|
+
if (policy == null) {
|
|
1202
|
+
throw new Error(
|
|
1203
|
+
`Could not resolve policy "${props.policyName}" in working state.`
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
return policy.id;
|
|
1207
|
+
}
|
|
972
1208
|
function resolvePermissionSetByName(props) {
|
|
973
1209
|
const permissionSet = props.state.identityCenter.permissionSetsByName[props.permissionSetName];
|
|
974
1210
|
if (permissionSet == null) {
|