@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
|
@@ -19,10 +19,12 @@ export class RdsAurora extends Construct {
|
|
|
19
19
|
databaseProxy;
|
|
20
20
|
databaseCredentials;
|
|
21
21
|
cfnCluster;
|
|
22
|
+
databaseNameValue;
|
|
22
23
|
constructor(scope, id, props) {
|
|
23
24
|
super(scope, id);
|
|
24
25
|
this.constructId = id;
|
|
25
26
|
this.port = props.port ?? RDS_DEFAULTS.DEFAULT_PORT;
|
|
27
|
+
this.databaseNameValue = props.databaseName ?? id;
|
|
26
28
|
// PostgreSQL fallback for direct usage - ensure engine and engineConfig match
|
|
27
29
|
this.engineConfig = props.engineConfig ?? DEFAULT_POSTGRES_ENGINE_CONFIG;
|
|
28
30
|
const { piEnabled, piConfig } = resolveDatabaseInsights(props.databaseInsights);
|
|
@@ -32,13 +34,13 @@ export class RdsAurora extends Construct {
|
|
|
32
34
|
: (props.credentials?.username ?? this.engineConfig.defaultUsername);
|
|
33
35
|
// Global secondary clusters import replicated secret instead of creating new
|
|
34
36
|
if (props.isGlobalSecondary) {
|
|
35
|
-
this.databaseCredentials = new Secret(this, `${
|
|
37
|
+
this.databaseCredentials = new Secret(this, `${this.databaseNameValue}Credentials`, {
|
|
36
38
|
secretName: ResourceNaming.credentialsSecretName(id),
|
|
37
39
|
importExisting: true
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
else {
|
|
41
|
-
this.databaseCredentials = new Secret(this, `${
|
|
43
|
+
this.databaseCredentials = new Secret(this, `${this.databaseNameValue}Credentials`, {
|
|
42
44
|
secretName: ResourceNaming.credentialsSecretName(id),
|
|
43
45
|
generateSecretString: {
|
|
44
46
|
secretStringTemplate: JSON.stringify({ username }),
|
|
@@ -49,11 +51,11 @@ export class RdsAurora extends Construct {
|
|
|
49
51
|
replicaRegions: props.secretReplicaRegions
|
|
50
52
|
});
|
|
51
53
|
}
|
|
52
|
-
const storageEncryptionKey = resolveStorageEncryptionKey(this,
|
|
53
|
-
const performanceInsightsKey = resolvePerformanceInsightsKey(this,
|
|
54
|
+
const storageEncryptionKey = resolveStorageEncryptionKey(this, this.databaseNameValue, props.encryption?.storageKey);
|
|
55
|
+
const performanceInsightsKey = resolvePerformanceInsightsKey(this, this.databaseNameValue, piEnabled, piConfig?.encryptionKey);
|
|
54
56
|
const clusterSecurityGroup = new SecurityGroup(this, `${id}SecurityGroup`, {
|
|
55
57
|
vpc: props.vpc,
|
|
56
|
-
description: `Security group for Aurora cluster ${
|
|
58
|
+
description: `Security group for Aurora cluster ${this.databaseNameValue}`
|
|
57
59
|
});
|
|
58
60
|
clusterSecurityGroup.addIngressRule(clusterSecurityGroup, Port.tcp(this.port));
|
|
59
61
|
// Allow VPC-wide access when enabled (avoids cross-stack cyclic dependencies)
|
|
@@ -73,8 +75,7 @@ export class RdsAurora extends Construct {
|
|
|
73
75
|
const writerSuffix = writerConfig.identifierSuffix;
|
|
74
76
|
const diMode = piConfig?.mode ?? "standard";
|
|
75
77
|
const performanceInsightsRetention = getDatabaseInsightsRetention(diMode);
|
|
76
|
-
const
|
|
77
|
-
const writer = ClusterInstance.serverlessV2(`${databaseName}Writer`, {
|
|
78
|
+
const writer = ClusterInstance.serverlessV2(`${this.databaseNameValue}Writer`, {
|
|
78
79
|
enablePerformanceInsights: writerPI,
|
|
79
80
|
performanceInsightEncryptionKey: writerPI
|
|
80
81
|
? performanceInsightsKey
|
|
@@ -94,9 +95,9 @@ export class RdsAurora extends Construct {
|
|
|
94
95
|
DatabaseClusterEngine.auroraPostgres({
|
|
95
96
|
version: AuroraPostgresEngineVersion.of("16.6", "16")
|
|
96
97
|
});
|
|
97
|
-
const parameterGroup = new ParameterGroup(this, `${
|
|
98
|
+
const parameterGroup = new ParameterGroup(this, `${this.databaseNameValue}ParameterGroup`, {
|
|
98
99
|
engine,
|
|
99
|
-
description: `Parameter group for ${
|
|
100
|
+
description: `Parameter group for ${this.databaseNameValue} with security defaults`,
|
|
100
101
|
parameters: this.engineConfig.sslParameters
|
|
101
102
|
});
|
|
102
103
|
// Use public subnets when publicly accessible, otherwise private
|
|
@@ -110,12 +111,14 @@ export class RdsAurora extends Construct {
|
|
|
110
111
|
securityGroups: [clusterSecurityGroup],
|
|
111
112
|
engine,
|
|
112
113
|
parameterGroup,
|
|
113
|
-
backup: {
|
|
114
|
+
backup: {
|
|
115
|
+
retention: Duration.days(props.backupRetention ?? RDS_DEFAULTS.BACKUP_RETENTION_DEFAULT_DAYS)
|
|
116
|
+
},
|
|
114
117
|
storageEncrypted: true,
|
|
115
118
|
...(storageEncryptionKey && { storageEncryptionKey }),
|
|
116
119
|
clusterIdentifier: props.clusterIdentifier?.toLowerCase() || ResourceNaming.clusterId(id),
|
|
117
|
-
monitoringInterval: props.monitoringInterval
|
|
118
|
-
preferredMaintenanceWindow: props.preferredMaintenanceWindow
|
|
120
|
+
monitoringInterval: props.monitoringInterval ?? RDS_DEFAULTS.MONITORING_INTERVAL,
|
|
121
|
+
preferredMaintenanceWindow: props.preferredMaintenanceWindow ??
|
|
119
122
|
RDS_DEFAULTS.PREFERRED_MAINTENANCE_WINDOW,
|
|
120
123
|
port: this.port,
|
|
121
124
|
removalPolicy: RemovalPolicy.SNAPSHOT,
|
|
@@ -132,26 +135,21 @@ export class RdsAurora extends Construct {
|
|
|
132
135
|
defaultDatabaseName: (props.databaseName || id.replace("Rds", "")).replace(/[^a-zA-Z0-9_]/g, "")
|
|
133
136
|
};
|
|
134
137
|
if (props.snapshotIdentifier) {
|
|
135
|
-
|
|
136
|
-
const snapshotCredentials = props.isGlobalSecondary
|
|
137
|
-
? {}
|
|
138
|
-
: {
|
|
139
|
-
credentials: SnapshotCredentials.fromSecret(this.databaseCredentials.secret)
|
|
140
|
-
};
|
|
141
|
-
this.databaseCluster = new DatabaseClusterFromSnapshot(this, `${id}Database`,
|
|
142
|
-
// Type assertion: CDK's SnapshotCredentials.username is string | undefined
|
|
143
|
-
// but DatabaseClusterFromSnapshotProps expects string. Works at runtime.
|
|
144
|
-
{
|
|
138
|
+
const snapshotProps = {
|
|
145
139
|
...baseClusterProps,
|
|
146
|
-
|
|
140
|
+
snapshotCredentials: props.isGlobalSecondary
|
|
141
|
+
? undefined
|
|
142
|
+
: SnapshotCredentials.fromSecret(this.databaseCredentials.secret),
|
|
147
143
|
snapshotIdentifier: props.snapshotIdentifier
|
|
148
|
-
}
|
|
144
|
+
};
|
|
145
|
+
this.databaseCluster = new DatabaseClusterFromSnapshot(this, `${id}Database`, snapshotProps);
|
|
149
146
|
}
|
|
150
147
|
else {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
const clusterProps = {
|
|
149
|
+
...baseClusterProps,
|
|
150
|
+
...primaryClusterProps
|
|
151
|
+
};
|
|
152
|
+
this.databaseCluster = new DatabaseCluster(this, `${id}Database`, clusterProps);
|
|
155
153
|
}
|
|
156
154
|
this.cfnCluster = this.databaseCluster.node.defaultChild;
|
|
157
155
|
// Global secondary clusters can't specify these properties
|
|
@@ -202,7 +200,7 @@ export class RdsAurora extends Construct {
|
|
|
202
200
|
: defaultPIEnabled;
|
|
203
201
|
return readerConfigs.map((config, index) => {
|
|
204
202
|
const enablePI = config.enableDatabaseInsights ?? defaultPI;
|
|
205
|
-
return ClusterInstance.serverlessV2(`${
|
|
203
|
+
return ClusterInstance.serverlessV2(`${this.databaseNameValue}Reader${index + 1}`, {
|
|
206
204
|
scaleWithWriter: config.scaleWithWriter ?? index === 0,
|
|
207
205
|
enablePerformanceInsights: enablePI,
|
|
208
206
|
performanceInsightEncryptionKey: enablePI ? piKey : undefined,
|
|
@@ -223,7 +221,7 @@ export class RdsAurora extends Construct {
|
|
|
223
221
|
const vpcSubnets = proxyConfig.vpcSubnets ?? {
|
|
224
222
|
subnetType: SubnetType.PRIVATE_WITH_EGRESS
|
|
225
223
|
};
|
|
226
|
-
this.databaseProxy = new DatabaseProxy(this, `${
|
|
224
|
+
this.databaseProxy = new DatabaseProxy(this, `${this.databaseNameValue}DatabaseProxy`, {
|
|
227
225
|
dbProxyName: ResourceNaming.proxyName(this.constructId),
|
|
228
226
|
proxyTarget: ProxyTarget.fromCluster(this.databaseCluster),
|
|
229
227
|
secrets: [this.databaseCredentials.secret],
|
|
@@ -237,12 +235,12 @@ export class RdsAurora extends Construct {
|
|
|
237
235
|
maxConnectionsPercent: proxyConfig.maxConnections,
|
|
238
236
|
maxIdleConnectionsPercent: proxyConfig.maxIdleConnections
|
|
239
237
|
});
|
|
240
|
-
addProxyCfnOutput(this, this.constructId,
|
|
238
|
+
addProxyCfnOutput(this, this.constructId, this.databaseNameValue, this.databaseProxy);
|
|
241
239
|
}
|
|
242
240
|
addSecretRotation(props) {
|
|
243
241
|
addMultiUserSecretRotation({
|
|
244
242
|
scope: this,
|
|
245
|
-
databaseName:
|
|
243
|
+
databaseName: this.databaseNameValue,
|
|
246
244
|
constructId: this.constructId,
|
|
247
245
|
engineConfig: this.engineConfig,
|
|
248
246
|
credentialsConfig: props.credentials,
|
|
@@ -264,6 +262,18 @@ export class RdsAurora extends Construct {
|
|
|
264
262
|
getCredentials() {
|
|
265
263
|
return this.databaseCredentials;
|
|
266
264
|
}
|
|
265
|
+
getClusterIdentifier() {
|
|
266
|
+
return this.databaseCluster.clusterIdentifier;
|
|
267
|
+
}
|
|
268
|
+
getSnapshotTarget() {
|
|
269
|
+
return { kind: "cluster", arn: this.databaseCluster.clusterArn };
|
|
270
|
+
}
|
|
271
|
+
getDatabaseName() {
|
|
272
|
+
return this.databaseNameValue;
|
|
273
|
+
}
|
|
274
|
+
getConnectionString() {
|
|
275
|
+
return `${this.engineConfig.family}://${this.getHostEndpoint()}:${this.getHostPort()}/${this.getDatabaseName()}`;
|
|
276
|
+
}
|
|
267
277
|
getCfnCluster() {
|
|
268
278
|
return this.cfnCluster;
|
|
269
279
|
}
|
|
@@ -2,8 +2,10 @@ import { type Duration } from "aws-cdk-lib";
|
|
|
2
2
|
import { Construct } from "constructs";
|
|
3
3
|
import { type IVpc, type Connections, type IConnectable } from "aws-cdk-lib/aws-ec2";
|
|
4
4
|
import { type IClusterEngine } from "aws-cdk-lib/aws-rds";
|
|
5
|
+
import { type ITopic } from "aws-cdk-lib/aws-sns";
|
|
5
6
|
import { type Secret } from "../secrets/index.js";
|
|
6
|
-
import { type
|
|
7
|
+
import { type RdsAlarmThresholds } from "../monitoring/index.js";
|
|
8
|
+
import { type EngineConfig, type ProxyConfig, type CredentialsConfig, type AuroraEncryptionConfig, type AuroraWriterConfig, type AuroraReadersConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
|
|
7
9
|
interface RdsAuroraGlobalProps {
|
|
8
10
|
vpc: IVpc;
|
|
9
11
|
databaseName: string;
|
|
@@ -49,6 +51,12 @@ interface RdsAuroraGlobalProps {
|
|
|
49
51
|
snapshotIdentifier?: string;
|
|
50
52
|
/** Username from the snapshot (required when restoring from snapshot to reset password) */
|
|
51
53
|
snapshotUsername?: string;
|
|
54
|
+
/** SNS topic for alarm notifications. Required for alarm creation. */
|
|
55
|
+
alertsTopic?: ITopic;
|
|
56
|
+
/** Alarm thresholds. false to disable, undefined for defaults, object to override. */
|
|
57
|
+
alarms?: RdsAlarmThresholds | false;
|
|
58
|
+
/** Application ID for alarm tagging. */
|
|
59
|
+
applicationId?: string;
|
|
52
60
|
}
|
|
53
61
|
export declare class RdsAuroraGlobal extends Construct implements IConnectable {
|
|
54
62
|
connections: Connections;
|
|
@@ -62,12 +70,17 @@ export declare class RdsAuroraGlobal extends Construct implements IConnectable {
|
|
|
62
70
|
constructor(scope: Construct, id: string, props: RdsAuroraGlobalProps);
|
|
63
71
|
getGlobalClusterIdentifier(): string;
|
|
64
72
|
getPrimaryClusterIdentifier(): string;
|
|
65
|
-
private getGlobalClusterEngineString;
|
|
66
73
|
private addGlobalCluster;
|
|
67
74
|
private addAuroraCluster;
|
|
68
75
|
private addOutputs;
|
|
69
76
|
getCredentials(): Secret;
|
|
70
77
|
getHostEndpoint(): string;
|
|
71
78
|
getHostPort(): string;
|
|
79
|
+
getClusterIdentifier(): string;
|
|
80
|
+
getSnapshotTarget(): Extract<SnapshotTarget, {
|
|
81
|
+
kind: "cluster";
|
|
82
|
+
}>;
|
|
83
|
+
getDatabaseName(): string;
|
|
84
|
+
getConnectionString(): string;
|
|
72
85
|
}
|
|
73
86
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CfnOutput, Stack } from "aws-cdk-lib";
|
|
1
|
+
import { ArnFormat, CfnOutput, Stack } from "aws-cdk-lib";
|
|
2
2
|
import { CfnGlobalCluster } from "aws-cdk-lib/aws-rds";
|
|
3
3
|
import { Construct } from "constructs";
|
|
4
4
|
import { RdsAurora } from "./rdsAurora.js";
|
|
@@ -32,41 +32,6 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
32
32
|
getPrimaryClusterIdentifier() {
|
|
33
33
|
return ResourceNaming.primaryClusterId(this.constructId);
|
|
34
34
|
}
|
|
35
|
-
getGlobalClusterEngineString() {
|
|
36
|
-
// Default to aurora-postgresql if no engine specified (matches existing behaviour)
|
|
37
|
-
if (!this.props.engine)
|
|
38
|
-
return "aurora-postgresql";
|
|
39
|
-
// Handle different engine formats safely using unknown and type guards
|
|
40
|
-
const engine = this.props.engine;
|
|
41
|
-
// CDK's IClusterEngine interface does not expose engineType/engine/name
|
|
42
|
-
// properties directly, but the concrete implementations (e.g. AuroraMysqlEngineVersion)
|
|
43
|
-
// do have them at runtime. Cast through unknown to probe these internal fields.
|
|
44
|
-
// CDK engine internals — may break on CDK upgrades. See rdsAuroraGlobal unit test.
|
|
45
|
-
const engineRecord = engine;
|
|
46
|
-
let engineType = engineRecord.engineType ?? engineRecord.engine ?? engineRecord.name;
|
|
47
|
-
// If the engine was provided as a raw string (unlikely but support it)
|
|
48
|
-
if (typeof engine === "string") {
|
|
49
|
-
engineType = engine;
|
|
50
|
-
}
|
|
51
|
-
// Fallback to toString() for Token-like objects
|
|
52
|
-
if (!engineType && typeof engineRecord.toString === "function") {
|
|
53
|
-
try {
|
|
54
|
-
engineType = engineRecord.toString();
|
|
55
|
-
}
|
|
56
|
-
catch (_e) {
|
|
57
|
-
// toString() may throw on CDK Token objects — fall back to undefined
|
|
58
|
-
engineType = undefined;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (typeof engineType !== "string")
|
|
62
|
-
return "aurora-postgresql";
|
|
63
|
-
// Normalise common forms: AURORA_POSTGRESQL -> aurora-postgresql, aurora_postgresql -> aurora-postgresql
|
|
64
|
-
const normalised = engineType.toLowerCase().replace(/_/g, "-");
|
|
65
|
-
// If the normalised value is just 'aurora', prefer the more specific postgres default
|
|
66
|
-
if (normalised === "aurora")
|
|
67
|
-
return "aurora-postgresql";
|
|
68
|
-
return normalised;
|
|
69
|
-
}
|
|
70
35
|
// create the CfnGlobalCluster only in the primary region
|
|
71
36
|
addGlobalCluster() {
|
|
72
37
|
if (this.props.primaryRegion !== this.currentRegion)
|
|
@@ -79,9 +44,7 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
79
44
|
if (this.primaryCluster) {
|
|
80
45
|
// Use the helper on RdsAurora to get the underlying L1 DBCluster (more reliable
|
|
81
46
|
// than relying on node.defaultChild which can vary depending on construct ordering)
|
|
82
|
-
primaryL1 =
|
|
83
|
-
this.primaryCluster.getCfnCluster &&
|
|
84
|
-
this.primaryCluster.getCfnCluster();
|
|
47
|
+
primaryL1 = this.primaryCluster.getCfnCluster();
|
|
85
48
|
if (primaryL1) {
|
|
86
49
|
sourceIdentifier = primaryL1.ref;
|
|
87
50
|
}
|
|
@@ -93,7 +56,7 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
93
56
|
// ensure the underlying primary DBCluster L1 has the globalClusterIdentifier set
|
|
94
57
|
if (primaryL1) {
|
|
95
58
|
// Make the CFN dependency explicit so the DBCluster is created before the GlobalCluster
|
|
96
|
-
this.globalCluster.
|
|
59
|
+
this.globalCluster.addDependency(primaryL1);
|
|
97
60
|
// IMPORTANT: do NOT set the primary DBCluster's `globalClusterIdentifier` here.
|
|
98
61
|
// If we set the primary DBCluster to reference the global cluster, CloudFormation
|
|
99
62
|
// will attempt to validate that the global cluster exists when creating the
|
|
@@ -125,7 +88,10 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
125
88
|
databaseInsights: this.props.databaseInsights,
|
|
126
89
|
deletionProtection: this.props.deletionProtection,
|
|
127
90
|
snapshotIdentifier: this.props.snapshotIdentifier,
|
|
128
|
-
snapshotUsername: this.props.snapshotUsername
|
|
91
|
+
snapshotUsername: this.props.snapshotUsername,
|
|
92
|
+
alertsTopic: this.props.alertsTopic,
|
|
93
|
+
alarms: this.props.alarms,
|
|
94
|
+
applicationId: this.props.applicationId
|
|
129
95
|
};
|
|
130
96
|
if (this.props.primaryRegion === this.currentRegion) {
|
|
131
97
|
// primary
|
|
@@ -153,8 +119,7 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
153
119
|
...commonConfig
|
|
154
120
|
});
|
|
155
121
|
// set the L1 DBCluster property so CloudFormation will join it to the global cluster
|
|
156
|
-
const regionalL1 = this.regionalCluster.getCfnCluster
|
|
157
|
-
this.regionalCluster.getCfnCluster();
|
|
122
|
+
const regionalL1 = this.regionalCluster.getCfnCluster();
|
|
158
123
|
if (regionalL1) {
|
|
159
124
|
regionalL1.globalClusterIdentifier = this.globalId;
|
|
160
125
|
// Enable write forwarding if requested
|
|
@@ -192,4 +157,35 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
192
157
|
return this.regionalCluster.getHostPort();
|
|
193
158
|
throw new Error("No Aurora cluster available to return port from");
|
|
194
159
|
}
|
|
160
|
+
getClusterIdentifier() {
|
|
161
|
+
return this.getPrimaryClusterIdentifier();
|
|
162
|
+
}
|
|
163
|
+
getSnapshotTarget() {
|
|
164
|
+
// The primary cluster lives in `primaryRegion`; pin region explicitly so
|
|
165
|
+
// a secondary-region stack still emits the correct ARN.
|
|
166
|
+
return {
|
|
167
|
+
kind: "cluster",
|
|
168
|
+
arn: Stack.of(this).formatArn({
|
|
169
|
+
service: "rds",
|
|
170
|
+
resource: "cluster",
|
|
171
|
+
resourceName: this.getPrimaryClusterIdentifier(),
|
|
172
|
+
region: this.props.primaryRegion,
|
|
173
|
+
arnFormat: ArnFormat.COLON_RESOURCE_NAME
|
|
174
|
+
})
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
getDatabaseName() {
|
|
178
|
+
if (this.primaryCluster)
|
|
179
|
+
return this.primaryCluster.getDatabaseName();
|
|
180
|
+
if (this.regionalCluster)
|
|
181
|
+
return this.regionalCluster.getDatabaseName();
|
|
182
|
+
throw new Error("No Aurora cluster available to return database name from");
|
|
183
|
+
}
|
|
184
|
+
getConnectionString() {
|
|
185
|
+
if (this.primaryCluster)
|
|
186
|
+
return this.primaryCluster.getConnectionString();
|
|
187
|
+
if (this.regionalCluster)
|
|
188
|
+
return this.regionalCluster.getConnectionString();
|
|
189
|
+
throw new Error("No Aurora cluster available to return connection string from");
|
|
190
|
+
}
|
|
195
191
|
}
|
|
@@ -8,4 +8,10 @@ export declare const RDS_DEFAULTS: Readonly<{
|
|
|
8
8
|
readonly MONITORING_INTERVAL: Duration;
|
|
9
9
|
/** SecretsManager rotation application version for multi-user rotation */
|
|
10
10
|
readonly ROTATION_APP_VERSION: "1.1.367";
|
|
11
|
+
/** Default backup retention in days — applied uniformly across Aurora and RDS Instance */
|
|
12
|
+
readonly BACKUP_RETENTION_DEFAULT_DAYS: 14;
|
|
13
|
+
/** Default instance type — primary and read-replica must stay in lockstep */
|
|
14
|
+
readonly DEFAULT_INSTANCE_TYPE: "t4g.large";
|
|
15
|
+
/** Default storage autoscaling ceiling (GiB) — applied to primary and replica */
|
|
16
|
+
readonly DEFAULT_MAX_ALLOCATED_STORAGE_GIB: 500;
|
|
11
17
|
}>;
|
|
@@ -7,5 +7,11 @@ export const RDS_DEFAULTS = Object.freeze({
|
|
|
7
7
|
/** 1 minute — balances monitoring granularity against CloudWatch costs */
|
|
8
8
|
MONITORING_INTERVAL: Duration.minutes(1),
|
|
9
9
|
/** SecretsManager rotation application version for multi-user rotation */
|
|
10
|
-
ROTATION_APP_VERSION: "1.1.367"
|
|
10
|
+
ROTATION_APP_VERSION: "1.1.367",
|
|
11
|
+
/** Default backup retention in days — applied uniformly across Aurora and RDS Instance */
|
|
12
|
+
BACKUP_RETENTION_DEFAULT_DAYS: 14,
|
|
13
|
+
/** Default instance type — primary and read-replica must stay in lockstep */
|
|
14
|
+
DEFAULT_INSTANCE_TYPE: "t4g.large",
|
|
15
|
+
/** Default storage autoscaling ceiling (GiB) — applied to primary and replica */
|
|
16
|
+
DEFAULT_MAX_ALLOCATED_STORAGE_GIB: 500
|
|
11
17
|
});
|
|
@@ -12,12 +12,12 @@ export declare const DEFAULT_POSTGRES_ENGINE_CONFIG: EngineConfig;
|
|
|
12
12
|
* - AWS managed / undefined → returns undefined (CDK default)
|
|
13
13
|
* - IKey → returns the key as-is
|
|
14
14
|
*/
|
|
15
|
-
export declare function resolveStorageEncryptionKey(scope: Construct, databaseName: string
|
|
15
|
+
export declare function resolveStorageEncryptionKey(scope: Construct, databaseName: string, storageKey: EncryptionKeySpec | undefined): IKey | undefined;
|
|
16
16
|
/**
|
|
17
17
|
* Resolve a Performance Insights encryption key spec into an IKey or undefined.
|
|
18
18
|
* Only creates a CMK when PI is enabled and CMK is requested.
|
|
19
19
|
*/
|
|
20
|
-
export declare function resolvePerformanceInsightsKey(scope: Construct, databaseName: string
|
|
20
|
+
export declare function resolvePerformanceInsightsKey(scope: Construct, databaseName: string, piEnabled: boolean, encryptionKey: EncryptionKeySpec | undefined): IKey | undefined;
|
|
21
21
|
/** Resolve the databaseInsights prop into an enabled flag and optional config object. */
|
|
22
22
|
export declare function resolveDatabaseInsights(databaseInsights: DatabaseInsightsConfig | false | undefined): {
|
|
23
23
|
piEnabled: boolean;
|
|
@@ -29,7 +29,7 @@ export declare function resolveDatabaseInsights(databaseInsights: DatabaseInsigh
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function addMultiUserSecretRotation(params: {
|
|
31
31
|
scope: Construct;
|
|
32
|
-
databaseName: string
|
|
32
|
+
databaseName: string;
|
|
33
33
|
constructId: string;
|
|
34
34
|
engineConfig: EngineConfig;
|
|
35
35
|
credentialsConfig: CredentialsConfig | undefined;
|
|
@@ -6,6 +6,7 @@ import { RDS_DEFAULTS } from "./rdsDefaults.js";
|
|
|
6
6
|
import { isAwsManagedKey, isCMKRequested } from "../../../utils/databaseTypes.js";
|
|
7
7
|
/** Default PostgreSQL engine configuration used by both Aurora and Instance constructs. */
|
|
8
8
|
export const DEFAULT_POSTGRES_ENGINE_CONFIG = {
|
|
9
|
+
family: "postgresql",
|
|
9
10
|
defaultUsername: "postgres",
|
|
10
11
|
sslParameters: { "rds.force_ssl": "1" },
|
|
11
12
|
rotationAppName: "SecretsManagerRDSPostgreSQLRotationMultiUser"
|
|
@@ -5,7 +5,7 @@ import { Construct } from "constructs";
|
|
|
5
5
|
import { SecurityGroup } from "../networking/securityGroup.js";
|
|
6
6
|
import { Secret } from "../secrets/index.js";
|
|
7
7
|
import { type StackBuilder } from "../base/awsStack.js";
|
|
8
|
-
import { type EngineConfig, type ProxyConfig, type ReadReplicaConfig, type CredentialsConfig, type EncryptionConfig, type DatabaseInsightsConfig } from "../../../utils/databaseTypes.js";
|
|
8
|
+
import { type EngineConfig, type ProxyConfig, type ReadReplicaConfig, type CredentialsConfig, type EncryptionConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
|
|
9
9
|
import type { ITopic } from "aws-cdk-lib/aws-sns";
|
|
10
10
|
import { type RdsAlarmThresholds } from "../monitoring/index.js";
|
|
11
11
|
interface RdsProps {
|
|
@@ -54,6 +54,7 @@ export declare class RdsInstance extends Construct implements IConnectable {
|
|
|
54
54
|
private databaseProxy?;
|
|
55
55
|
private databaseProxySecurityGroup?;
|
|
56
56
|
private readReplicaSecurityGroup?;
|
|
57
|
+
private databaseNameValue;
|
|
57
58
|
private readonly constructId;
|
|
58
59
|
constructor(scope: Construct, id: string, props: RdsProps);
|
|
59
60
|
private addDatabase;
|
|
@@ -63,6 +64,12 @@ export declare class RdsInstance extends Construct implements IConnectable {
|
|
|
63
64
|
getHostEndpoint(): string;
|
|
64
65
|
getHostPort(): string;
|
|
65
66
|
getCredentials(): Secret;
|
|
67
|
+
getInstanceIdentifier(): string;
|
|
68
|
+
getSnapshotTarget(): Extract<SnapshotTarget, {
|
|
69
|
+
kind: "instance";
|
|
70
|
+
}>;
|
|
71
|
+
getDatabaseName(): string;
|
|
72
|
+
getConnectionString(): string;
|
|
66
73
|
static build(id: string, props: RdsProps): (sb: StackBuilder) => Construct;
|
|
67
74
|
}
|
|
68
75
|
export {};
|
|
@@ -26,12 +26,14 @@ export class RdsInstance extends Construct {
|
|
|
26
26
|
databaseProxy;
|
|
27
27
|
databaseProxySecurityGroup;
|
|
28
28
|
readReplicaSecurityGroup;
|
|
29
|
+
databaseNameValue;
|
|
29
30
|
constructId;
|
|
30
31
|
constructor(scope, id, props) {
|
|
31
32
|
super(scope, id);
|
|
32
33
|
this.constructId = id;
|
|
33
|
-
this.port = props.port
|
|
34
|
+
this.port = props.port ?? RDS_DEFAULTS.DEFAULT_PORT;
|
|
34
35
|
this.vpc = props.vpc;
|
|
36
|
+
this.databaseNameValue = props.databaseName ?? id.replace("Rds", "");
|
|
35
37
|
// PostgreSQL fallback for direct usage - ensure engine and engineConfig match
|
|
36
38
|
this.engineConfig = props.engineConfig ?? DEFAULT_POSTGRES_ENGINE_CONFIG;
|
|
37
39
|
this.addDatabase(props);
|
|
@@ -62,7 +64,7 @@ export class RdsInstance extends Construct {
|
|
|
62
64
|
const username = props.snapshotIdentifier && props.snapshotUsername
|
|
63
65
|
? props.snapshotUsername
|
|
64
66
|
: (props.credentials?.username ?? this.engineConfig.defaultUsername);
|
|
65
|
-
this.databaseCredentials = new Secret(this, `${
|
|
67
|
+
this.databaseCredentials = new Secret(this, `${this.databaseNameValue}Credentials`, {
|
|
66
68
|
secretName: ResourceNaming.credentialsSecretName(this.constructId),
|
|
67
69
|
generateSecretString: {
|
|
68
70
|
secretStringTemplate: JSON.stringify({
|
|
@@ -73,9 +75,9 @@ export class RdsInstance extends Construct {
|
|
|
73
75
|
generateStringKey: "password"
|
|
74
76
|
}
|
|
75
77
|
});
|
|
76
|
-
this.databaseSecurityGroup = new SecurityGroup(this, `${
|
|
78
|
+
this.databaseSecurityGroup = new SecurityGroup(this, `${this.databaseNameValue}SecurityGroup`, {
|
|
77
79
|
vpc: this.vpc,
|
|
78
|
-
description: `Security group for RDS database instance ${
|
|
80
|
+
description: `Security group for RDS database instance ${this.databaseNameValue}`
|
|
79
81
|
});
|
|
80
82
|
// Self-referencing rule for multi-AZ communication
|
|
81
83
|
this.databaseSecurityGroup.addIngressRule(this.databaseSecurityGroup, Port.tcp(this.port));
|
|
@@ -83,9 +85,9 @@ export class RdsInstance extends Construct {
|
|
|
83
85
|
securityGroups: [this.databaseSecurityGroup],
|
|
84
86
|
defaultPort: Port.tcp(this.port)
|
|
85
87
|
});
|
|
86
|
-
const storageEncryptionKey = resolveStorageEncryptionKey(this,
|
|
88
|
+
const storageEncryptionKey = resolveStorageEncryptionKey(this, this.databaseNameValue, props.encryption?.storageKey);
|
|
87
89
|
const { piEnabled, piConfig } = resolveDatabaseInsights(props.databaseInsights);
|
|
88
|
-
const performanceInsightsEncryptionKey = resolvePerformanceInsightsKey(this,
|
|
90
|
+
const performanceInsightsEncryptionKey = resolvePerformanceInsightsKey(this, this.databaseNameValue, piEnabled, piConfig?.encryptionKey);
|
|
89
91
|
const diMode = piConfig?.mode ?? "standard";
|
|
90
92
|
const performanceInsightsRetention = piEnabled
|
|
91
93
|
? getDatabaseInsightsRetention(diMode)
|
|
@@ -94,9 +96,9 @@ export class RdsInstance extends Construct {
|
|
|
94
96
|
DatabaseInstanceEngine.postgres({
|
|
95
97
|
version: PostgresEngineVersion.VER_17_5
|
|
96
98
|
});
|
|
97
|
-
const parameterGroup = new ParameterGroup(this, `${
|
|
99
|
+
const parameterGroup = new ParameterGroup(this, `${this.databaseNameValue}ParameterGroup`, {
|
|
98
100
|
engine,
|
|
99
|
-
description: `Parameter group for ${
|
|
101
|
+
description: `Parameter group for ${this.databaseNameValue} with security defaults`,
|
|
100
102
|
parameters: this.engineConfig.sslParameters
|
|
101
103
|
});
|
|
102
104
|
// Use PUBLIC subnet for publiclyAccessible databases (e.g., tinkerer tier without NAT)
|
|
@@ -112,8 +114,9 @@ export class RdsInstance extends Construct {
|
|
|
112
114
|
engine,
|
|
113
115
|
parameterGroup,
|
|
114
116
|
allocatedStorage: props.allocatedStorage,
|
|
115
|
-
backupRetention: props.backupRetention
|
|
116
|
-
|
|
117
|
+
backupRetention: props.backupRetention ??
|
|
118
|
+
Duration.days(RDS_DEFAULTS.BACKUP_RETENTION_DEFAULT_DAYS),
|
|
119
|
+
preferredBackupWindow: props.preferredBackupWindow ?? "02:00-03:00",
|
|
117
120
|
storageEncrypted: true,
|
|
118
121
|
storageEncryptionKey,
|
|
119
122
|
storageType: StorageType.GP3,
|
|
@@ -124,21 +127,20 @@ export class RdsInstance extends Construct {
|
|
|
124
127
|
performanceInsightEncryptionKey: performanceInsightsEncryptionKey,
|
|
125
128
|
performanceInsightRetention: performanceInsightsRetention,
|
|
126
129
|
instanceIdentifier: ResourceNaming.dbInstanceId(this.constructId),
|
|
127
|
-
instanceType: props.instanceType
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
monitoringInterval: props.monitoringInterval || RDS_DEFAULTS.MONITORING_INTERVAL,
|
|
130
|
+
instanceType: new InstanceType(props.instanceType ?? RDS_DEFAULTS.DEFAULT_INSTANCE_TYPE),
|
|
131
|
+
maxAllocatedStorage: props.maxAllocatedStorage ??
|
|
132
|
+
RDS_DEFAULTS.DEFAULT_MAX_ALLOCATED_STORAGE_GIB,
|
|
133
|
+
monitoringInterval: props.monitoringInterval ?? RDS_DEFAULTS.MONITORING_INTERVAL,
|
|
132
134
|
multiAz: props.multiAz !== false,
|
|
133
135
|
port: this.port,
|
|
134
136
|
deletionProtection: props.deletionProtection ?? true,
|
|
135
|
-
preferredMaintenanceWindow: props.preferredMaintenanceWindow
|
|
137
|
+
preferredMaintenanceWindow: props.preferredMaintenanceWindow ??
|
|
136
138
|
RDS_DEFAULTS.PREFERRED_MAINTENANCE_WINDOW,
|
|
137
139
|
publiclyAccessible: props.publiclyAccessible ?? false
|
|
138
140
|
};
|
|
139
141
|
if (props.snapshotIdentifier) {
|
|
140
142
|
// Create from snapshot
|
|
141
|
-
this.database = new DatabaseInstanceFromSnapshot(this, `${
|
|
143
|
+
this.database = new DatabaseInstanceFromSnapshot(this, `${this.databaseNameValue}Database`, {
|
|
142
144
|
...commonInstanceProps,
|
|
143
145
|
snapshotIdentifier: props.snapshotIdentifier,
|
|
144
146
|
// For snapshots, credentials are used to reset the password
|
|
@@ -147,7 +149,7 @@ export class RdsInstance extends Construct {
|
|
|
147
149
|
}
|
|
148
150
|
else {
|
|
149
151
|
// Create new instance
|
|
150
|
-
this.database = new DatabaseInstance(this, `${
|
|
152
|
+
this.database = new DatabaseInstance(this, `${this.databaseNameValue}Database`, {
|
|
151
153
|
...commonInstanceProps,
|
|
152
154
|
databaseName: props.databaseName,
|
|
153
155
|
credentials: Credentials.fromSecret(this.databaseCredentials.secret)
|
|
@@ -157,7 +159,7 @@ export class RdsInstance extends Construct {
|
|
|
157
159
|
rotateSecret(props) {
|
|
158
160
|
this.masterSecret = addMultiUserSecretRotation({
|
|
159
161
|
scope: this,
|
|
160
|
-
databaseName:
|
|
162
|
+
databaseName: this.databaseNameValue,
|
|
161
163
|
constructId: this.constructId,
|
|
162
164
|
engineConfig: this.engineConfig,
|
|
163
165
|
credentialsConfig: props.credentials,
|
|
@@ -173,13 +175,13 @@ export class RdsInstance extends Construct {
|
|
|
173
175
|
const vpcSubnets = proxyConfig.vpcSubnets ?? {
|
|
174
176
|
subnetType: SubnetType.PRIVATE_WITH_EGRESS
|
|
175
177
|
};
|
|
176
|
-
this.databaseProxySecurityGroup = new SecurityGroup(this, `${
|
|
178
|
+
this.databaseProxySecurityGroup = new SecurityGroup(this, `${this.databaseNameValue}ProxySecurityGroup`, {
|
|
177
179
|
vpc: this.vpc,
|
|
178
|
-
description: `Security group for RDS Proxy for ${
|
|
180
|
+
description: `Security group for RDS Proxy for ${this.databaseNameValue}`
|
|
179
181
|
});
|
|
180
182
|
// Allow proxy to connect to database
|
|
181
183
|
this.databaseSecurityGroup.addIngressRule(this.databaseProxySecurityGroup, Port.tcp(this.port), "Allow RDS Proxy to connect to database");
|
|
182
|
-
this.databaseProxy = new DatabaseProxy(this, `${
|
|
184
|
+
this.databaseProxy = new DatabaseProxy(this, `${this.databaseNameValue}DatabaseProxy`, {
|
|
183
185
|
dbProxyName: ResourceNaming.proxyName(this.constructId),
|
|
184
186
|
proxyTarget: ProxyTarget.fromInstance(this.database),
|
|
185
187
|
secrets: [this.databaseCredentials.secret],
|
|
@@ -193,22 +195,24 @@ export class RdsInstance extends Construct {
|
|
|
193
195
|
maxConnectionsPercent: proxyConfig.maxConnections,
|
|
194
196
|
maxIdleConnectionsPercent: proxyConfig.maxIdleConnections
|
|
195
197
|
});
|
|
196
|
-
addProxyCfnOutput(this, this.constructId,
|
|
198
|
+
addProxyCfnOutput(this, this.constructId, this.databaseNameValue, this.databaseProxy);
|
|
197
199
|
}
|
|
198
200
|
addReadReplica(props) {
|
|
199
201
|
if (!props.readReplica)
|
|
200
202
|
return;
|
|
201
203
|
const replicaConfig = props.readReplica;
|
|
202
|
-
const replicaInstanceType = replicaConfig.instanceType ??
|
|
204
|
+
const replicaInstanceType = replicaConfig.instanceType ??
|
|
205
|
+
props.instanceType ??
|
|
206
|
+
RDS_DEFAULTS.DEFAULT_INSTANCE_TYPE;
|
|
203
207
|
const { piEnabled, piConfig } = resolveDatabaseInsights(props.databaseInsights);
|
|
204
208
|
const readReplicaPerformanceInsightsKey = piEnabled && isCMKRequested(piConfig?.encryptionKey)
|
|
205
|
-
? new CustomerManagedKey(this, `${
|
|
206
|
-
aliasName: `cmk/rds/${
|
|
209
|
+
? new CustomerManagedKey(this, `${this.databaseNameValue}ReadReplicaReaderInsightsKey`, {
|
|
210
|
+
aliasName: `cmk/rds/${this.databaseNameValue}/ReadReplicaInsightsKey`
|
|
207
211
|
}).key
|
|
208
212
|
: undefined;
|
|
209
|
-
this.readReplicaSecurityGroup = new SecurityGroup(this, `${
|
|
213
|
+
this.readReplicaSecurityGroup = new SecurityGroup(this, `${this.databaseNameValue}ReadReplicaSecurityGroup`, {
|
|
210
214
|
vpc: this.vpc,
|
|
211
|
-
description: `Security group for RDS read replica of ${
|
|
215
|
+
description: `Security group for RDS read replica of ${this.databaseNameValue}`
|
|
212
216
|
});
|
|
213
217
|
// Allow primary database to replicate to read replica
|
|
214
218
|
this.readReplicaSecurityGroup.addIngressRule(this.databaseSecurityGroup, Port.tcp(this.port), "Allow primary database to replicate to read replica");
|
|
@@ -217,10 +221,10 @@ export class RdsInstance extends Construct {
|
|
|
217
221
|
// Without this waiter, the final snapshot creation fails.
|
|
218
222
|
const instanceId = ResourceNaming.dbInstanceId(this.constructId);
|
|
219
223
|
const waiterTimeout = Duration.minutes(10);
|
|
220
|
-
const deletionWaiter = new CustomResource(this, `${
|
|
224
|
+
const deletionWaiter = new CustomResource(this, `${this.databaseNameValue}DeletionWaiter`, {
|
|
221
225
|
runtime: Runtime.NODEJS_22_X,
|
|
222
226
|
timeout: waiterTimeout.plus(Duration.seconds(30)),
|
|
223
|
-
lambdaDescription: `${
|
|
227
|
+
lambdaDescription: `${this.databaseNameValue} deletion waiter`,
|
|
224
228
|
inlineCode: `
|
|
225
229
|
const { RDSClient } = require('@aws-sdk/client-rds');
|
|
226
230
|
const { waitUntilDBInstanceAvailable } = require('@aws-sdk/client-rds');
|
|
@@ -266,7 +270,7 @@ exports.handler = async (event) => {
|
|
|
266
270
|
}
|
|
267
271
|
});
|
|
268
272
|
deletionWaiter.resource.node.addDependency(this.database);
|
|
269
|
-
const readReplica = new DatabaseInstanceReadReplica(this, `${
|
|
273
|
+
const readReplica = new DatabaseInstanceReadReplica(this, `${this.databaseNameValue}ReadReplica`, {
|
|
270
274
|
sourceDatabaseInstance: this.database,
|
|
271
275
|
vpc: this.vpc,
|
|
272
276
|
vpcSubnets: {
|
|
@@ -287,12 +291,13 @@ exports.handler = async (event) => {
|
|
|
287
291
|
instanceIdentifier: ResourceNaming.readReplicaId(this.constructId),
|
|
288
292
|
instanceType: new InstanceType(replicaInstanceType),
|
|
289
293
|
availabilityZone: replicaConfig.availabilityZone,
|
|
290
|
-
maxAllocatedStorage: props.maxAllocatedStorage
|
|
291
|
-
|
|
294
|
+
maxAllocatedStorage: props.maxAllocatedStorage ??
|
|
295
|
+
RDS_DEFAULTS.DEFAULT_MAX_ALLOCATED_STORAGE_GIB,
|
|
296
|
+
monitoringInterval: props.monitoringInterval ?? RDS_DEFAULTS.MONITORING_INTERVAL,
|
|
292
297
|
multiAz: props.multiAz !== false,
|
|
293
298
|
port: this.port,
|
|
294
299
|
deletionProtection: props.deletionProtection ?? true,
|
|
295
|
-
preferredMaintenanceWindow: props.preferredMaintenanceWindow
|
|
300
|
+
preferredMaintenanceWindow: props.preferredMaintenanceWindow ??
|
|
296
301
|
RDS_DEFAULTS.PREFERRED_MAINTENANCE_WINDOW
|
|
297
302
|
});
|
|
298
303
|
readReplica.node.addDependency(deletionWaiter.resource);
|
|
@@ -311,6 +316,18 @@ exports.handler = async (event) => {
|
|
|
311
316
|
getCredentials() {
|
|
312
317
|
return this.databaseCredentials;
|
|
313
318
|
}
|
|
319
|
+
getInstanceIdentifier() {
|
|
320
|
+
return this.database.instanceIdentifier;
|
|
321
|
+
}
|
|
322
|
+
getSnapshotTarget() {
|
|
323
|
+
return { kind: "instance", arn: this.database.instanceArn };
|
|
324
|
+
}
|
|
325
|
+
getDatabaseName() {
|
|
326
|
+
return this.databaseNameValue;
|
|
327
|
+
}
|
|
328
|
+
getConnectionString() {
|
|
329
|
+
return `${this.engineConfig.family}://${this.getHostEndpoint()}:${this.getHostPort()}/${this.getDatabaseName()}`;
|
|
330
|
+
}
|
|
314
331
|
static build(id, props) {
|
|
315
332
|
return (sb) => {
|
|
316
333
|
const newProps = {
|