@fjall/components-infrastructure 0.96.0 → 0.99.1
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/dist/lib/app.d.ts +68 -1
- package/dist/lib/app.js +113 -4
- package/dist/lib/config/aws/__t17fixture.d.ts +1 -0
- package/dist/lib/config/aws/__t17fixture.js +3 -0
- package/dist/lib/config/aws/__t17fixtureType.d.ts +2 -0
- package/dist/lib/config/aws/__t17fixtureType.js +1 -0
- package/dist/lib/config/aws/alarmTopic.js +8 -4
- package/dist/lib/config/aws/cloudTrail.js +1 -1
- package/dist/lib/config/aws/disasterRecovery.js +11 -16
- package/dist/lib/config/aws/ecrDefaultImage.d.ts +0 -1
- package/dist/lib/config/aws/ecrDefaultImage.js +13 -23
- package/dist/lib/config/aws/identityCenter.d.ts +10 -3
- package/dist/lib/config/aws/identityCenter.js +101 -37
- package/dist/lib/config/aws/identityCenterGroupMembership.js +8 -2
- package/dist/lib/config/aws/identityCenterMembership.d.ts +11 -0
- package/dist/lib/config/aws/identityCenterMembership.js +61 -0
- package/dist/lib/config/aws/index.d.ts +1 -1
- package/dist/lib/config/aws/index.js +1 -1
- package/dist/lib/config/aws/ipam.js +6 -11
- package/dist/lib/config/aws/oidcConnector.js +5 -1
- package/dist/lib/config/aws/scpPreset.js +4 -1
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +1 -0
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +4 -0
- package/dist/lib/patterns/aws/account.js +2 -4
- package/dist/lib/patterns/aws/apexDomainPattern.js +10 -10
- package/dist/lib/patterns/aws/bastionFactory.d.ts +10 -0
- package/dist/lib/patterns/aws/bastionFactory.js +29 -0
- package/dist/lib/patterns/aws/buildkite.d.ts +2 -2
- package/dist/lib/patterns/aws/buildkite.js +51 -97
- package/dist/lib/patterns/aws/cdn.js +1 -1
- package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +172 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.js +600 -0
- package/dist/lib/patterns/aws/compute.d.ts +4 -6
- package/dist/lib/patterns/aws/compute.js +7 -13
- package/dist/lib/patterns/aws/computeEcs.d.ts +93 -5
- package/dist/lib/patterns/aws/computeEcs.js +867 -37
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +528 -25
- package/dist/lib/patterns/aws/computeEcsTypes.js +10 -0
- package/dist/lib/patterns/aws/computeLambda.d.ts +0 -5
- package/dist/lib/patterns/aws/computeLambda.js +1 -2
- package/dist/lib/patterns/aws/database.d.ts +50 -8
- package/dist/lib/patterns/aws/database.js +183 -27
- package/dist/lib/patterns/aws/domain.js +6 -4
- package/dist/lib/patterns/aws/index.d.ts +1 -0
- package/dist/lib/patterns/aws/index.js +1 -0
- package/dist/lib/patterns/aws/interfaces/compute.d.ts +7 -1
- package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
- package/dist/lib/patterns/aws/interfaces/database.js +17 -3
- package/dist/lib/patterns/aws/interfaces/index.d.ts +2 -1
- package/dist/lib/patterns/aws/interfaces/index.js +3 -1
- package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
- package/dist/lib/patterns/aws/messaging.d.ts +66 -10
- package/dist/lib/patterns/aws/messaging.js +115 -20
- package/dist/lib/patterns/aws/network.js +16 -7
- package/dist/lib/patterns/aws/organisation.d.ts +4 -0
- package/dist/lib/patterns/aws/organisation.js +22 -4
- package/dist/lib/patterns/aws/storage.d.ts +1 -2
- package/dist/lib/patterns/aws/storage.js +3 -2
- package/dist/lib/patterns/aws/vpcPeer.js +3 -1
- package/dist/lib/resources/aws/analytics/clickhouse.js +18 -9
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +24 -9
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +61 -10
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +3 -3
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +3 -3
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +7 -1
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -1
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +53 -3
- package/dist/lib/resources/aws/base/awsStack.js +4 -2
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
- package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
- package/dist/lib/resources/aws/compute/ec2.js +163 -23
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
- package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
- package/dist/lib/resources/aws/compute/ecs.js +42 -2
- package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
- package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
- package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
- package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
- package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +102 -6
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +173 -13
- package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
- package/dist/lib/resources/aws/compute/index.d.ts +2 -0
- package/dist/lib/resources/aws/compute/index.js +2 -0
- package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
- package/dist/lib/resources/aws/compute/lambda.js +30 -38
- package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
- package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
- package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
- package/dist/lib/resources/aws/compute/samApplication.js +27 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.js +157 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
- package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
- package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
- package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
- package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
- package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
- package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
- package/dist/lib/resources/aws/iam/delegationRole.js +1 -1
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
- package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
- package/dist/lib/resources/aws/logging/logGroup.js +0 -11
- package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
- package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
- package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
- package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
- package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
- package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
- package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
- package/dist/lib/resources/aws/messaging/index.js +2 -0
- package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
- package/dist/lib/resources/aws/messaging/schedule.js +64 -0
- package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
- package/dist/lib/resources/aws/messaging/subscription.js +67 -0
- package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
- package/dist/lib/resources/aws/messaging/utils.js +10 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
- package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
- package/dist/lib/resources/aws/monitoring/index.js +2 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
- package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -4
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +17 -13
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -5
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
- package/dist/lib/resources/aws/networking/domainCertificate.js +6 -4
- package/dist/lib/resources/aws/networking/hostedZone.js +6 -5
- package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
- package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
- package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
- package/dist/lib/resources/aws/networking/vpc.js +4 -1
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +21 -3
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
- package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
- package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
- package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
- package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
- package/dist/lib/resources/aws/secrets/secret.js +4 -3
- package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
- package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
- package/dist/lib/resources/aws/storage/ecr.js +5 -5
- package/dist/lib/resources/aws/storage/index.d.ts +1 -0
- package/dist/lib/resources/aws/storage/index.js +1 -0
- package/dist/lib/resources/aws/storage/s3.js +10 -3
- package/dist/lib/resources/aws/utilities/customResource.js +18 -9
- package/dist/lib/synth_dump.d.ts +1 -0
- package/dist/lib/synth_dump.js +42 -0
- package/dist/lib/utils/cdkContext.d.ts +2 -0
- package/dist/lib/utils/cdkContext.js +4 -2
- package/dist/lib/utils/connections.js +6 -0
- package/dist/lib/utils/connector.d.ts +12 -0
- package/dist/lib/utils/costAllocationTags.d.ts +9 -0
- package/dist/lib/utils/costAllocationTags.js +11 -1
- package/dist/lib/utils/databaseTypes.d.ts +14 -0
- package/dist/lib/utils/getConfig.d.ts +2 -0
- package/dist/lib/utils/getConfig.js +2 -0
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils/index.js +1 -0
- package/dist/lib/utils/manifestWriter.d.ts +6 -89
- package/dist/lib/utils/manifestWriter.js +36 -23
- package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
- package/dist/lib/utils/migrationVersionResolvers.js +2 -0
- package/dist/lib/utils/orgConfigParser.js +2 -1
- package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
- package/dist/lib/utils/resolveAlertsTopic.js +30 -0
- package/dist/lib/utils/validationLogger.js +6 -3
- package/package.json +22 -19
|
@@ -5,6 +5,7 @@ import { AwsCustomResource } from "../../resources/aws/utilities/awsCustomResour
|
|
|
5
5
|
import { stripAndCamelCase } from "../../utils/stripAndCamelCase.js";
|
|
6
6
|
import { Group, PermissionSet, Assignment } from "../../resources/aws/iam/identityCenter/index.js";
|
|
7
7
|
import { ManagedPolicy, Role } from "../../resources/aws/iam/index.js";
|
|
8
|
+
import { IdentityCenterMembership } from "./identityCenterMembership.js";
|
|
8
9
|
const defaultPermissionSets = {
|
|
9
10
|
AdministratorAccess: {
|
|
10
11
|
Policy: "arn:aws:iam::aws:policy/AdministratorAccess",
|
|
@@ -19,15 +20,64 @@ const defaultPermissionSets = {
|
|
|
19
20
|
Description: "Permission set for associated Billing policy"
|
|
20
21
|
}
|
|
21
22
|
};
|
|
23
|
+
// CreateAccountAssignment has a 15-outstanding-async limit. Batching at 8
|
|
24
|
+
// keeps headroom for CFN's internal retries within the same backoff window.
|
|
25
|
+
const ASSIGNMENT_BATCH_SIZE = 8;
|
|
22
26
|
export class IdentityCenter extends NestedStack {
|
|
23
27
|
identityStoreId;
|
|
24
28
|
identityCenterArn;
|
|
25
29
|
listInstancesRole;
|
|
30
|
+
accountsConfig;
|
|
31
|
+
customTags;
|
|
32
|
+
groupIds = {};
|
|
26
33
|
constructor(scope, id, props) {
|
|
27
34
|
super(scope, id, props);
|
|
35
|
+
this.accountsConfig = props.accounts;
|
|
36
|
+
this.customTags = props.tags;
|
|
28
37
|
this.createListInstancesRole();
|
|
29
38
|
this.listIdentityCenterInstance();
|
|
30
|
-
|
|
39
|
+
for (const [name, config] of Object.entries(defaultPermissionSets)) {
|
|
40
|
+
this.createPermissionSetAndAssignments(name, config, {
|
|
41
|
+
managedPolicies: [config.Policy]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
declarePermissionSets(customs) {
|
|
46
|
+
for (const [name, config] of Object.entries(customs)) {
|
|
47
|
+
if (this.groupIds[name] !== undefined) {
|
|
48
|
+
throw new Error(`Permission set "${name}" already declared (collision with default or prior declaration)`);
|
|
49
|
+
}
|
|
50
|
+
const primaryPolicy = config.managedPolicies[0];
|
|
51
|
+
if (primaryPolicy === undefined) {
|
|
52
|
+
throw new Error(`Permission set "${name}" must declare at least one managed policy.`);
|
|
53
|
+
}
|
|
54
|
+
this.createPermissionSetAndAssignments(name, {
|
|
55
|
+
Policy: primaryPolicy,
|
|
56
|
+
...(config.description !== undefined && {
|
|
57
|
+
Description: config.description
|
|
58
|
+
})
|
|
59
|
+
}, {
|
|
60
|
+
managedPolicies: config.managedPolicies,
|
|
61
|
+
...(config.sessionDuration !== undefined && {
|
|
62
|
+
sessionDuration: config.sessionDuration
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
assignGroupMembers(members) {
|
|
68
|
+
for (const [groupName, emails] of Object.entries(members)) {
|
|
69
|
+
if (emails.length === 0)
|
|
70
|
+
continue;
|
|
71
|
+
const groupId = this.groupIds[groupName];
|
|
72
|
+
if (groupId === undefined) {
|
|
73
|
+
throw new Error(`Cannot assign members to undeclared group "${groupName}". Declare via declarePermissionSets() first, or use one of the defaults: AdministratorAccess, ReadOnlyAccess, Billing.`);
|
|
74
|
+
}
|
|
75
|
+
new IdentityCenterMembership(this, `${groupName}Members`, {
|
|
76
|
+
identityStoreId: this.identityStoreId,
|
|
77
|
+
groupId,
|
|
78
|
+
groupMembers: emails
|
|
79
|
+
});
|
|
80
|
+
}
|
|
31
81
|
}
|
|
32
82
|
createListInstancesRole() {
|
|
33
83
|
this.listInstancesRole = new Role(this, "IdentityCenterCustomResourceRole", {
|
|
@@ -49,15 +99,17 @@ export class IdentityCenter extends NestedStack {
|
|
|
49
99
|
});
|
|
50
100
|
}
|
|
51
101
|
listIdentityCenterInstance() {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
MaxResults: 1
|
|
58
|
-
},
|
|
59
|
-
physicalResourceId: customResources.PhysicalResourceId.of("listIdentityCenterInstance")
|
|
102
|
+
const listInstancesCall = {
|
|
103
|
+
service: "sso-admin",
|
|
104
|
+
action: "listInstances",
|
|
105
|
+
parameters: {
|
|
106
|
+
MaxResults: 1
|
|
60
107
|
},
|
|
108
|
+
physicalResourceId: customResources.PhysicalResourceId.of("listIdentityCenterInstance")
|
|
109
|
+
};
|
|
110
|
+
const customResource = new AwsCustomResource(this, "ListIdentityCenterInstanceResource", {
|
|
111
|
+
onCreate: listInstancesCall,
|
|
112
|
+
onUpdate: listInstancesCall,
|
|
61
113
|
role: this.listInstancesRole,
|
|
62
114
|
resourceType: "Custom::IamIdentityCenter"
|
|
63
115
|
});
|
|
@@ -74,37 +126,49 @@ export class IdentityCenter extends NestedStack {
|
|
|
74
126
|
exportName: "identityStoreId"
|
|
75
127
|
});
|
|
76
128
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
129
|
+
createPermissionSetAndAssignments(name, config, permissionSetOverrides) {
|
|
130
|
+
const group = new Group(this, `${name}Group`, {
|
|
131
|
+
displayName: name,
|
|
132
|
+
identityStoreId: this.identityStoreId,
|
|
133
|
+
description: `Group for associated ${name} permission set`
|
|
134
|
+
});
|
|
135
|
+
this.groupIds[name] = group.getGroupId();
|
|
136
|
+
const permissionSet = new PermissionSet(this, `PermissionSet${name}`, {
|
|
137
|
+
name: name,
|
|
138
|
+
instanceArn: this.identityCenterArn,
|
|
139
|
+
...(config.Description !== undefined && {
|
|
140
|
+
description: config.Description
|
|
141
|
+
}),
|
|
142
|
+
managedPolicies: permissionSetOverrides.managedPolicies,
|
|
143
|
+
...(permissionSetOverrides.sessionDuration !== undefined && {
|
|
144
|
+
sessionDuration: permissionSetOverrides.sessionDuration
|
|
145
|
+
}),
|
|
146
|
+
...(this.customTags !== undefined && { tags: this.customTags })
|
|
147
|
+
});
|
|
148
|
+
permissionSet.node.addDependency(group);
|
|
149
|
+
new CfnOutput(this, `${name}GroupId`, {
|
|
150
|
+
key: `${name}GroupId`,
|
|
151
|
+
value: group.getGroupId(),
|
|
152
|
+
exportName: `${name}GroupId`
|
|
153
|
+
});
|
|
154
|
+
const assignments = [];
|
|
155
|
+
for (const [accountName, accountId] of Object.entries(this.accountsConfig)) {
|
|
156
|
+
const assignment = new Assignment(this, `${stripAndCamelCase(accountName)}${name}Assignment`, {
|
|
86
157
|
instanceArn: this.identityCenterArn,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
new CfnOutput(this, `${name}GroupId`, {
|
|
93
|
-
key: `${name}GroupId`,
|
|
94
|
-
value: group.getGroupId(),
|
|
95
|
-
exportName: `${name}GroupId`
|
|
158
|
+
permissionSetArn: permissionSet.getPermissionSetArn(),
|
|
159
|
+
principalType: "GROUP",
|
|
160
|
+
principalId: group.getGroupId(),
|
|
161
|
+
targetType: "AWS_ACCOUNT",
|
|
162
|
+
targetId: accountId
|
|
96
163
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
targetType: "AWS_ACCOUNT",
|
|
104
|
-
targetId: accountId
|
|
105
|
-
});
|
|
106
|
-
assignment.node.addDependency(permissionSet);
|
|
164
|
+
assignment.node.addDependency(permissionSet);
|
|
165
|
+
if (assignments.length >= ASSIGNMENT_BATCH_SIZE) {
|
|
166
|
+
const dependency = assignments[assignments.length - ASSIGNMENT_BATCH_SIZE];
|
|
167
|
+
if (dependency !== undefined) {
|
|
168
|
+
assignment.node.addDependency(dependency);
|
|
169
|
+
}
|
|
107
170
|
}
|
|
171
|
+
assignments.push(assignment);
|
|
108
172
|
}
|
|
109
173
|
}
|
|
110
174
|
}
|
|
@@ -74,7 +74,10 @@ export class IdentityCenterGroupMembership extends NestedStack {
|
|
|
74
74
|
UserId: userId
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
|
-
physicalResourceId: customResources.PhysicalResourceId.of(`recreateGroupMembership${memberSuffix}`)
|
|
77
|
+
physicalResourceId: customResources.PhysicalResourceId.of(`recreateGroupMembership${memberSuffix}`),
|
|
78
|
+
// createGroupMembership throws ConflictException when the
|
|
79
|
+
// membership already exists — keeps onUpdate idempotent.
|
|
80
|
+
ignoreErrorCodesMatching: "ConflictException"
|
|
78
81
|
},
|
|
79
82
|
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
80
83
|
});
|
|
@@ -86,7 +89,10 @@ export class IdentityCenterGroupMembership extends NestedStack {
|
|
|
86
89
|
parameters: {
|
|
87
90
|
IdentityStoreId: identityStoreId,
|
|
88
91
|
MembershipId: groupMembershipId.getResponseField("MembershipId")
|
|
89
|
-
}
|
|
92
|
+
},
|
|
93
|
+
// deleteGroupMembership throws ResourceNotFoundException when
|
|
94
|
+
// the membership is already gone — keeps onDelete idempotent.
|
|
95
|
+
ignoreErrorCodesMatching: "ResourceNotFoundException"
|
|
90
96
|
},
|
|
91
97
|
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
92
98
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NestedStack, type NestedStackProps } from "aws-cdk-lib";
|
|
2
|
+
import { type Construct } from "constructs";
|
|
3
|
+
export interface IdentityCenterMembershipProps extends NestedStackProps {
|
|
4
|
+
identityStoreId: string;
|
|
5
|
+
groupId: string;
|
|
6
|
+
groupMembers: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function validateIdentityCenterMembershipProps(props: IdentityCenterMembershipProps): void;
|
|
9
|
+
export declare class IdentityCenterMembership extends NestedStack {
|
|
10
|
+
constructor(scope: Construct, id: string, props: IdentityCenterMembershipProps);
|
|
11
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as customResources from "aws-cdk-lib/custom-resources";
|
|
2
|
+
import { NestedStack } from "aws-cdk-lib";
|
|
3
|
+
import { AwsCustomResource } from "../../resources/aws/utilities/awsCustomResource.js";
|
|
4
|
+
import { GroupMembership } from "../../resources/aws/iam/identityCenter/groupMembership.js";
|
|
5
|
+
import { stripAndCamelCase } from "../../utils/stripAndCamelCase.js";
|
|
6
|
+
const IDENTITY_STORE_SERVICE = "identityStore";
|
|
7
|
+
export function validateIdentityCenterMembershipProps(props) {
|
|
8
|
+
if (!props.identityStoreId) {
|
|
9
|
+
throw new Error("IdentityCenterMembership requires identityStoreId from the parent IdentityCenter construct.");
|
|
10
|
+
}
|
|
11
|
+
if (!props.groupId) {
|
|
12
|
+
throw new Error("IdentityCenterMembership requires groupId from a Group construct.");
|
|
13
|
+
}
|
|
14
|
+
if (props.groupMembers.length === 0) {
|
|
15
|
+
throw new Error("IdentityCenterMembership requires at least one member email. Empty groups should be skipped at the caller.");
|
|
16
|
+
}
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
for (const member of props.groupMembers) {
|
|
19
|
+
if (!member.includes("@")) {
|
|
20
|
+
throw new Error(`IdentityCenterMembership: "${member}" is not a valid email — Identity Center memberships look up users by UserName (email)`);
|
|
21
|
+
}
|
|
22
|
+
if (seen.has(member)) {
|
|
23
|
+
throw new Error(`Duplicate member "${member}" in IdentityCenterMembership groupMembers.`);
|
|
24
|
+
}
|
|
25
|
+
seen.add(member);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class IdentityCenterMembership extends NestedStack {
|
|
29
|
+
constructor(scope, id, props) {
|
|
30
|
+
super(scope, id, props);
|
|
31
|
+
validateIdentityCenterMembershipProps(props);
|
|
32
|
+
for (const member of props.groupMembers) {
|
|
33
|
+
const [localPart] = member.split("@");
|
|
34
|
+
const suffix = stripAndCamelCase(localPart ?? member);
|
|
35
|
+
const listUsersCall = {
|
|
36
|
+
service: IDENTITY_STORE_SERVICE,
|
|
37
|
+
action: "listUsers",
|
|
38
|
+
parameters: {
|
|
39
|
+
IdentityStoreId: props.identityStoreId,
|
|
40
|
+
Filters: [
|
|
41
|
+
{
|
|
42
|
+
AttributePath: "UserName",
|
|
43
|
+
AttributeValue: member
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
physicalResourceId: customResources.PhysicalResourceId.of(`listUsers${suffix}`)
|
|
48
|
+
};
|
|
49
|
+
const userLookup = new AwsCustomResource(this, `User${suffix}`, {
|
|
50
|
+
onCreate: listUsersCall,
|
|
51
|
+
onUpdate: listUsersCall
|
|
52
|
+
});
|
|
53
|
+
const userId = userLookup.getResponseField("Users.0.UserId");
|
|
54
|
+
new GroupMembership(this, `Membership${suffix}`, {
|
|
55
|
+
identityStoreId: props.identityStoreId,
|
|
56
|
+
groupId: props.groupId,
|
|
57
|
+
userId
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./identityCenter.js";
|
|
2
|
+
export * from "./identityCenterMembership.js";
|
|
2
3
|
export * from "./ipam.js";
|
|
3
4
|
export * from "./ecrDefaultImage.js";
|
|
4
|
-
export * from "./eventBus.js";
|
|
5
5
|
export * from "./oidcConnector.js";
|
|
6
6
|
export * from "./platform.js";
|
|
7
7
|
export * from "./accountMonitoringRole.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./identityCenter.js";
|
|
2
|
+
export * from "./identityCenterMembership.js";
|
|
2
3
|
export * from "./ipam.js";
|
|
3
4
|
export * from "./ecrDefaultImage.js";
|
|
4
|
-
export * from "./eventBus.js";
|
|
5
5
|
export * from "./oidcConnector.js";
|
|
6
6
|
export * from "./platform.js";
|
|
7
7
|
export * from "./accountMonitoringRole.js";
|
|
@@ -2,13 +2,6 @@ import { CfnOutput } from "aws-cdk-lib";
|
|
|
2
2
|
import { Construct } from "constructs";
|
|
3
3
|
import { Ipam as IpamClass } from "../../resources/aws/networking/ipam.js";
|
|
4
4
|
import { getConfig } from "../../utils/getConfig.js";
|
|
5
|
-
function operatingRegions(regions) {
|
|
6
|
-
const operationRegionArray = [];
|
|
7
|
-
for (const region of regions) {
|
|
8
|
-
operationRegionArray.push({ regionName: region });
|
|
9
|
-
}
|
|
10
|
-
return operationRegionArray;
|
|
11
|
-
}
|
|
12
5
|
export class Ipam extends Construct {
|
|
13
6
|
privateDefaultScopeId;
|
|
14
7
|
constructor(scope, id, props) {
|
|
@@ -18,8 +11,10 @@ export class Ipam extends Construct {
|
|
|
18
11
|
const regions = props?.regions || config.allRegions;
|
|
19
12
|
// Fallback to at least the current region if no regions configured
|
|
20
13
|
const operationalRegions = regions.length > 0 ? regions : [config.region];
|
|
21
|
-
const ipam = new IpamClass(this, "
|
|
22
|
-
operatingRegions:
|
|
14
|
+
const ipam = new IpamClass(this, "Ipam", {
|
|
15
|
+
operatingRegions: operationalRegions.map((regionName) => ({
|
|
16
|
+
regionName
|
|
17
|
+
})),
|
|
23
18
|
tags: [
|
|
24
19
|
{
|
|
25
20
|
key: "fjall:costAllocation:environment",
|
|
@@ -28,8 +23,8 @@ export class Ipam extends Construct {
|
|
|
28
23
|
]
|
|
29
24
|
});
|
|
30
25
|
this.privateDefaultScopeId = ipam.attrPrivateDefaultScopeId;
|
|
31
|
-
new CfnOutput(this, "
|
|
32
|
-
key: "
|
|
26
|
+
new CfnOutput(this, "IpamPrivateDefaultScopeId", {
|
|
27
|
+
key: "IpamPrivateDefaultScopeId",
|
|
33
28
|
value: ipam.attrPrivateDefaultScopeId,
|
|
34
29
|
exportName: "IpamPrivateDefaultScopeId"
|
|
35
30
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CfnOutput, Duration } from "aws-cdk-lib";
|
|
2
2
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
3
3
|
import { Construct } from "constructs";
|
|
4
|
+
import { Role } from "../../resources/aws/iam/role.js";
|
|
4
5
|
export class OidcConnector extends Construct {
|
|
5
6
|
deployRoleArn;
|
|
6
7
|
constructor(scope, id, props) {
|
|
@@ -10,10 +11,13 @@ export class OidcConnector extends Construct {
|
|
|
10
11
|
const provider = new iam.OpenIdConnectProvider(this, "OidcProvider", {
|
|
11
12
|
url: issuerUrl,
|
|
12
13
|
clientIds: ["sts.amazonaws.com"],
|
|
14
|
+
// Placeholder thumbprint. CDK auto-resolves at deploy time for known IdPs;
|
|
15
|
+
// STS trust is enforced via the OIDC issuer URL + `:sub` / `:aud` match.
|
|
13
16
|
thumbprints: ["0000000000000000000000000000000000000000"]
|
|
14
17
|
});
|
|
15
|
-
const deployRole = new
|
|
18
|
+
const deployRole = new Role(this, "DeployRole", {
|
|
16
19
|
roleName: `FjallDeploy${props.fjallOrgId}`,
|
|
20
|
+
path: "/fjall/",
|
|
17
21
|
maxSessionDuration: Duration.hours(1),
|
|
18
22
|
assumedBy: new iam.FederatedPrincipal(provider.openIdConnectProviderArn, {
|
|
19
23
|
StringEquals: { [`${issuerDomain}:aud`]: "sts.amazonaws.com" },
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
2
|
import { OrganisationPolicy } from "../../resources/aws/organisation/organisationPolicy.js";
|
|
3
|
+
// Path prefix `/fjall/` is load-bearing: without it, a member-account admin
|
|
4
|
+
// could bypass protect-* SCPs by creating a `FjallDeploy*` role at the
|
|
5
|
+
// default path.
|
|
3
6
|
const EXEMPT_ROLE_PATTERNS = [
|
|
4
|
-
"arn:aws:iam::*:role/FjallDeploy*",
|
|
7
|
+
"arn:aws:iam::*:role/fjall/FjallDeploy*",
|
|
5
8
|
"arn:aws:iam::*:role/OrganizationAccountAccessRole"
|
|
6
9
|
];
|
|
7
10
|
const SCP_BYTE_LIMIT = 5120;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CfnOutput, Stack } from "aws-cdk-lib";
|
|
2
|
-
import { EcrDefaultImage,
|
|
2
|
+
import { EcrDefaultImage, SharedAlarmTopic } from "../../config/aws/index.js";
|
|
3
3
|
import { ManagementEventsTrail } from "../../config/aws/cloudTrail.js";
|
|
4
4
|
import { OidcConnector } from "../../config/aws/oidcConnector.js";
|
|
5
5
|
import { AccountMonitoringRole } from "../../config/aws/accountMonitoringRole.js";
|
|
@@ -42,7 +42,6 @@ export class Account extends Stack {
|
|
|
42
42
|
exportName: "AccountId",
|
|
43
43
|
description: "AWS Account ID for this account"
|
|
44
44
|
});
|
|
45
|
-
const eventBus = new DefaultEventBus(this, "EventBus");
|
|
46
45
|
new SharedAlarmTopic(this, "AlarmTopic");
|
|
47
46
|
const isStandaloneAccount = this.constructor === Account;
|
|
48
47
|
const ipamPoolId = this.node.tryGetContext("ipamPoolId");
|
|
@@ -71,8 +70,7 @@ export class Account extends Stack {
|
|
|
71
70
|
});
|
|
72
71
|
new EcrDefaultImage(this, "EcrDefaultImage", {
|
|
73
72
|
region: this.resolvedRegion,
|
|
74
|
-
accountId: this.account
|
|
75
|
-
eventBusArn: eventBus.defaultEventBusArn.value
|
|
73
|
+
accountId: this.account
|
|
76
74
|
});
|
|
77
75
|
const environment = config.environment ?? "unknown";
|
|
78
76
|
if (config.disasterRecoveryRegion) {
|
|
@@ -5,6 +5,7 @@ import { DomainCertificate } from "../../resources/aws/networking/domainCertific
|
|
|
5
5
|
import { NsRecord } from "../../resources/aws/networking/dnsRecord/index.js";
|
|
6
6
|
import { composeTypedDnsRecords } from "./dnsRecordComposer.js";
|
|
7
7
|
import { toPascalCase, getSafeZoneName } from "../../utils/capitaliseString.js";
|
|
8
|
+
import { resolveOrgId } from "../../utils/cdkContext.js";
|
|
8
9
|
/**
|
|
9
10
|
* Composition for `registrar: "route53"`. Creates (or imports) the apex
|
|
10
11
|
* `HostedZone`, wires child-account delegations via `NsRecord` (pointing at
|
|
@@ -21,12 +22,15 @@ import { toPascalCase, getSafeZoneName } from "../../utils/capitaliseString.js";
|
|
|
21
22
|
*/
|
|
22
23
|
export function composeApexDomain(scope, props) {
|
|
23
24
|
const safeZone = toPascalCase(getSafeZoneName(props.zoneName));
|
|
25
|
+
// Gotcha: the cross-account DelegationRole imports CFN export `OrganisationId`
|
|
26
|
+
// from the org/account stack — only published when an `orgId` CDK context
|
|
27
|
+
// value is set. Single-account deploys would roll back at synth without
|
|
28
|
+
// this gate.
|
|
29
|
+
const inOrganisation = resolveOrgId(scope.node) !== undefined;
|
|
24
30
|
const hostedZoneConstruct = new HostedZone(scope, `${safeZone}HostedZone`, {
|
|
25
31
|
zoneName: props.zoneName,
|
|
26
32
|
hostedZoneId: props.hostedZoneId,
|
|
27
|
-
|
|
28
|
-
// not manage IAM themselves.
|
|
29
|
-
createDelegationRole: props.hostedZoneId === undefined,
|
|
33
|
+
createDelegationRole: props.hostedZoneId === undefined && inOrganisation,
|
|
30
34
|
costAllocationEnvironment: props.costAllocationEnvironment,
|
|
31
35
|
costAllocationDomain: props.zoneName
|
|
32
36
|
});
|
|
@@ -52,13 +56,9 @@ export function composeApexDomain(scope, props) {
|
|
|
52
56
|
const childZoneName = `${delegation.subdomain}.${props.zoneName}`;
|
|
53
57
|
const safeChild = toPascalCase(getSafeZoneName(childZoneName));
|
|
54
58
|
const childExports = getDomainExportNames(childZoneName);
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// via Fn.split). The child HZ id import is declared as a cross-phase
|
|
59
|
-
// dependency — if the child stack has not deployed, CFN fails at deploy.
|
|
60
|
-
const nameserversExportName = childExports.hostedZoneId.replace(/-hosted-zone-id$/, "-nameservers");
|
|
61
|
-
const nameserversToken = Fn.importValue(nameserversExportName);
|
|
59
|
+
// Cross-phase dependency: child stack must deploy first; CFN fails here
|
|
60
|
+
// at deploy if the nameservers export does not yet exist.
|
|
61
|
+
const nameserversToken = Fn.importValue(childExports.nameservers);
|
|
62
62
|
new NsRecord(scope, `${safeZone}Delegation${safeChild}${index}`, {
|
|
63
63
|
zone: hostedZoneConstruct.hostedZone,
|
|
64
64
|
zoneName: props.zoneName,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
2
|
+
import { Ec2Instance } from "../../resources/aws/compute/ec2.js";
|
|
3
|
+
import { type AwsStack } from "../../resources/index.js";
|
|
4
|
+
export interface BastionConfig {
|
|
5
|
+
instanceType?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BastionResult {
|
|
8
|
+
bastion: Ec2Instance;
|
|
9
|
+
}
|
|
10
|
+
export declare function createBastion(networkStack: AwsStack, appName: string, stackPrefix: string, vpc: IVpc, config: BastionConfig | true): BastionResult;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CfnOutput } from "aws-cdk-lib";
|
|
2
|
+
import { Ec2Instance } from "../../resources/aws/compute/ec2.js";
|
|
3
|
+
import { toPascalCase } from "../../utils/capitaliseString.js";
|
|
4
|
+
export function createBastion(networkStack, appName, stackPrefix, vpc, config) {
|
|
5
|
+
const instanceType = typeof config === "object" && config.instanceType
|
|
6
|
+
? config.instanceType
|
|
7
|
+
: "t4g.micro";
|
|
8
|
+
const bastionId = `${stackPrefix}Bastion`;
|
|
9
|
+
const scope = networkStack.getStack();
|
|
10
|
+
const bastion = new Ec2Instance(scope, bastionId, {
|
|
11
|
+
serviceName: `${stackPrefix}Bastion`,
|
|
12
|
+
instanceType,
|
|
13
|
+
vpc,
|
|
14
|
+
enableSSH: false,
|
|
15
|
+
minCapacity: 1,
|
|
16
|
+
maxCapacity: 1
|
|
17
|
+
});
|
|
18
|
+
networkStack.addConstruct(bastion);
|
|
19
|
+
const outputPrefix = toPascalCase(appName);
|
|
20
|
+
new CfnOutput(scope, `${outputPrefix}BastionInstanceId`, {
|
|
21
|
+
value: bastion.getAutoScalingGroup().autoScalingGroupName,
|
|
22
|
+
description: "Bastion ASG name for SSM tunnel discovery"
|
|
23
|
+
});
|
|
24
|
+
new CfnOutput(scope, `${outputPrefix}BastionSecurityGroupId`, {
|
|
25
|
+
value: bastion.asgSecurityGroup.securityGroupId,
|
|
26
|
+
description: "Bastion security group ID"
|
|
27
|
+
});
|
|
28
|
+
return { bastion };
|
|
29
|
+
}
|
|
@@ -2,7 +2,7 @@ import { type StackProps, Stack } from "aws-cdk-lib";
|
|
|
2
2
|
import { InstanceType } from "aws-cdk-lib/aws-ec2";
|
|
3
3
|
import { type Construct } from "constructs";
|
|
4
4
|
import { type KeyValue } from "../../types.js";
|
|
5
|
-
declare enum
|
|
5
|
+
export declare enum AgentRelease {
|
|
6
6
|
STABLE = "stable",
|
|
7
7
|
BETA = "beta",
|
|
8
8
|
EDGE = "edge"
|
|
@@ -11,7 +11,7 @@ export interface BuildkiteProps extends StackProps {
|
|
|
11
11
|
accountId?: string;
|
|
12
12
|
elasticStackVersion: string;
|
|
13
13
|
keyName: string;
|
|
14
|
-
buildkiteAgentRelease:
|
|
14
|
+
buildkiteAgentRelease: AgentRelease;
|
|
15
15
|
buildkiteAgentTags: string;
|
|
16
16
|
buildkiteAgentTimestampLines: boolean;
|
|
17
17
|
buildkiteAgentExperiments: string;
|