@fjall/components-infrastructure 32.0.0 → 33.1.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 +15 -76
- package/dist/lib/app.d.ts +1 -1
- package/dist/lib/config/audit.js +2 -1
- package/dist/lib/config/aws/identityCentreConfig.d.ts +1 -1
- package/dist/lib/config/aws/identityCentreConfig.js +1 -1
- package/dist/lib/config/aws/scpPreset.js +1 -2
- package/dist/lib/lambda-assets/cert-generator/asset/index.js +126 -0
- package/dist/lib/patterns/aws/buildkite/buildkite.d.ts +1 -1
- package/dist/lib/patterns/aws/buildkite/buildkite.js +1 -1
- package/dist/lib/patterns/aws/buildkite/factory.d.ts +2 -2
- package/dist/lib/patterns/aws/buildkite/pins.d.ts +2 -2
- package/dist/lib/patterns/aws/buildkite/pins.js +3 -4
- package/dist/lib/patterns/aws/buildkite/schema.d.ts +1 -1
- package/dist/lib/patterns/aws/buildkite/schema.js +1 -1
- package/dist/lib/patterns/aws/buildkite/userData.d.ts +1 -1
- package/dist/lib/patterns/aws/buildkite/userData.js +1 -1
- package/dist/lib/patterns/aws/buildkite.d.ts +1 -1
- package/dist/lib/patterns/aws/buildkite.js +1 -1
- package/dist/lib/patterns/aws/cdn.d.ts +14 -0
- package/dist/lib/patterns/aws/cdn.js +31 -3
- package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +8 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.js +19 -3
- package/dist/lib/patterns/aws/clickhouseTls/types.d.ts +1 -1
- package/dist/lib/patterns/aws/compute.js +4 -2
- package/dist/lib/patterns/aws/computeEcs.d.ts +7 -0
- package/dist/lib/patterns/aws/computeEcs.js +26 -3
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +30 -7
- package/dist/lib/patterns/aws/computeLambda.d.ts +12 -0
- package/dist/lib/patterns/aws/computeLambda.js +2 -0
- package/dist/lib/patterns/aws/computePropApplicability.js +2 -0
- package/dist/lib/patterns/aws/database.d.ts +14 -0
- package/dist/lib/patterns/aws/database.js +16 -6
- package/dist/lib/patterns/aws/interfaces/pattern.d.ts +6 -6
- package/dist/lib/patterns/aws/messaging.js +4 -1
- package/dist/lib/patterns/aws/patternDomain.d.ts +1 -1
- package/dist/lib/patterns/aws/patternDomain.js +1 -1
- package/dist/lib/patterns/aws/payload.js +7 -5
- package/dist/lib/patterns/aws/staticSite.d.ts +6 -6
- package/dist/lib/patterns/aws/staticSite.js +9 -6
- package/dist/lib/patterns/aws/storage.d.ts +8 -0
- package/dist/lib/patterns/aws/storage.js +1 -0
- package/dist/lib/resources/aws/cdn/cloudFront.d.ts +2 -0
- package/dist/lib/resources/aws/cdn/cloudFront.js +1 -0
- package/dist/lib/resources/aws/cdn/responseHeadersPolicy.d.ts +1 -1
- package/dist/lib/resources/aws/cdn/responseHeadersPolicy.js +1 -1
- package/dist/lib/resources/aws/compute/applicationLoadBalancer.d.ts +10 -0
- package/dist/lib/resources/aws/compute/applicationLoadBalancer.js +7 -1
- package/dist/lib/resources/aws/compute/ec2.d.ts +2 -2
- package/dist/lib/resources/aws/compute/ec2.js +1 -1
- package/dist/lib/resources/aws/compute/ecs.d.ts +11 -0
- package/dist/lib/resources/aws/compute/ecs.js +51 -6
- package/dist/lib/resources/aws/compute/ecsContext.d.ts +10 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.js +3 -1
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +4 -1
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +31 -8
- package/dist/lib/resources/aws/compute/lambda.d.ts +18 -1
- package/dist/lib/resources/aws/compute/lambda.js +21 -3
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +5 -5
- package/dist/lib/resources/aws/database/clickhouseConstants.js +5 -5
- package/dist/lib/resources/aws/database/dynamodb.d.ts +19 -0
- package/dist/lib/resources/aws/database/dynamodb.js +13 -2
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +11 -0
- package/dist/lib/resources/aws/database/rdsAurora.js +24 -3
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +11 -1
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +1 -0
- package/dist/lib/resources/aws/database/rdsDefaults.d.ts +0 -2
- package/dist/lib/resources/aws/database/rdsDefaults.js +0 -2
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +11 -0
- package/dist/lib/resources/aws/database/rdsInstance.js +19 -4
- package/dist/lib/resources/aws/iam/identityCenter/user.d.ts +1 -1
- package/dist/lib/resources/aws/iam/identityCenter/user.js +1 -1
- package/dist/lib/resources/aws/logging/accessLogBucket.d.ts +22 -0
- package/dist/lib/resources/aws/logging/accessLogBucket.js +41 -0
- package/dist/lib/resources/aws/logging/index.d.ts +1 -0
- package/dist/lib/resources/aws/logging/index.js +1 -0
- package/dist/lib/resources/aws/messaging/sns.d.ts +14 -5
- package/dist/lib/resources/aws/messaging/sns.js +7 -1
- package/dist/lib/resources/aws/secrets/index.d.ts +1 -0
- package/dist/lib/resources/aws/secrets/index.js +1 -0
- package/dist/lib/resources/aws/secrets/stackEncryptionKey.d.ts +47 -0
- package/dist/lib/resources/aws/secrets/stackEncryptionKey.js +114 -0
- package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +2 -3
- package/dist/lib/resources/aws/storage/bucketDeployment.js +2 -3
- package/dist/lib/resources/aws/storage/s3.d.ts +13 -1
- package/dist/lib/resources/aws/storage/s3.js +6 -3
- package/dist/lib/utils/backupTierMapping.d.ts +10 -2
- package/dist/lib/utils/backupTierMapping.js +3 -1
- package/package.json +5 -4
|
@@ -3,6 +3,7 @@ import { Connections, type IConnectable } from "aws-cdk-lib/aws-ec2";
|
|
|
3
3
|
import { Construct } from "constructs";
|
|
4
4
|
import type { StackBuilder } from "../base/awsStack.js";
|
|
5
5
|
import type { ApplicationListener, ApplicationLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
|
|
6
|
+
import { StackEncryptionKey } from "../secrets/stackEncryptionKey.js";
|
|
6
7
|
import { type EcsClusterProps } from "./ecsTypes.js";
|
|
7
8
|
import { type EcsIngressProfile } from "./ingressProfile.js";
|
|
8
9
|
export * from "./ecsTypes.js";
|
|
@@ -65,6 +66,16 @@ export default class EcsCluster extends Construct implements IConnectable {
|
|
|
65
66
|
private outputName;
|
|
66
67
|
private loadBalancerDisabled;
|
|
67
68
|
private directAccessEnabled;
|
|
69
|
+
private readonly containerInsightsEnabled;
|
|
70
|
+
/**
|
|
71
|
+
* The stack's shared key when the app backup tier encrypts (resolved once,
|
|
72
|
+
* here); undefined otherwise. Read by the patterns layer for the log
|
|
73
|
+
* groups it creates beside the cluster's own, so the tier is consulted in
|
|
74
|
+
* one place.
|
|
75
|
+
*/
|
|
76
|
+
readonly encryptionKey: StackEncryptionKey | undefined;
|
|
77
|
+
private readonly loadBalancerDeletionProtection;
|
|
78
|
+
private readonly loadBalancerAccessLogs;
|
|
68
79
|
private priorityState;
|
|
69
80
|
constructor(scope: Construct, id: string, props: EcsClusterProps);
|
|
70
81
|
private get ctx();
|
|
@@ -3,6 +3,9 @@ import { Connections, Port } from "aws-cdk-lib/aws-ec2";
|
|
|
3
3
|
import { Construct } from "constructs";
|
|
4
4
|
import { CfnOutput, Aspects } from "aws-cdk-lib";
|
|
5
5
|
import { processConnections } from "../../../utils/connections.js";
|
|
6
|
+
import { tierDefault } from "../../../utils/backupTierMapping.js";
|
|
7
|
+
import { envAwareRemovalPolicyDefault } from "../../../utils/removalPolicy.js";
|
|
8
|
+
import { StackEncryptionKey } from "../secrets/stackEncryptionKey.js";
|
|
6
9
|
import { DEFAULT_FRAMEWORK_LOG_RETENTION, LogGroup } from "../logging/logGroup.js";
|
|
7
10
|
import { stackScopedExportName } from "../../../utils/exportNaming.js";
|
|
8
11
|
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
@@ -84,6 +87,16 @@ export default class EcsCluster extends Construct {
|
|
|
84
87
|
outputName;
|
|
85
88
|
loadBalancerDisabled;
|
|
86
89
|
directAccessEnabled;
|
|
90
|
+
containerInsightsEnabled;
|
|
91
|
+
/**
|
|
92
|
+
* The stack's shared key when the app backup tier encrypts (resolved once,
|
|
93
|
+
* here); undefined otherwise. Read by the patterns layer for the log
|
|
94
|
+
* groups it creates beside the cluster's own, so the tier is consulted in
|
|
95
|
+
* one place.
|
|
96
|
+
*/
|
|
97
|
+
encryptionKey;
|
|
98
|
+
loadBalancerDeletionProtection;
|
|
99
|
+
loadBalancerAccessLogs;
|
|
87
100
|
// ALB priority management
|
|
88
101
|
priorityState = {
|
|
89
102
|
nextPriority: 100,
|
|
@@ -98,6 +111,21 @@ export default class EcsCluster extends Construct {
|
|
|
98
111
|
this.directAccessEnabled = props.cluster?.directAccess === true;
|
|
99
112
|
this.loadBalancerDisabled =
|
|
100
113
|
props.cluster?.loadBalancer === false || this.directAccessEnabled;
|
|
114
|
+
// Tier-owned defaults resolve exactly once, here; every helper reads the
|
|
115
|
+
// resolved value from ctx. An explicit prop is the override.
|
|
116
|
+
const tier = props.appBackupTier;
|
|
117
|
+
this.containerInsightsEnabled =
|
|
118
|
+
props.containerInsights ?? tierDefault(tier, "containerInsights");
|
|
119
|
+
this.encryptionKey = tierDefault(tier, "customerManagedKeys")
|
|
120
|
+
? StackEncryptionKey.of(this)
|
|
121
|
+
: undefined;
|
|
122
|
+
this.loadBalancerDeletionProtection =
|
|
123
|
+
props.cluster?.loadBalancerDeletionProtection ??
|
|
124
|
+
(tierDefault(tier, "deletionProtection") &&
|
|
125
|
+
envAwareRemovalPolicyDefault() === "RETAIN");
|
|
126
|
+
this.loadBalancerAccessLogs =
|
|
127
|
+
props.cluster?.loadBalancerAccessLogs ??
|
|
128
|
+
tierDefault(tier, "albAccessLogs");
|
|
101
129
|
validateEcsClusterProps(props, this);
|
|
102
130
|
this.cluster = this.addCluster(props);
|
|
103
131
|
for (const serviceProps of props.services) {
|
|
@@ -161,7 +189,10 @@ export default class EcsCluster extends Construct {
|
|
|
161
189
|
cluster: this.cluster,
|
|
162
190
|
outputName: this.outputName,
|
|
163
191
|
loadBalancerDisabled: this.loadBalancerDisabled,
|
|
164
|
-
directAccessEnabled: this.directAccessEnabled
|
|
192
|
+
directAccessEnabled: this.directAccessEnabled,
|
|
193
|
+
encryptionKey: this.encryptionKey,
|
|
194
|
+
loadBalancerDeletionProtection: this.loadBalancerDeletionProtection,
|
|
195
|
+
loadBalancerAccessLogs: this.loadBalancerAccessLogs
|
|
165
196
|
};
|
|
166
197
|
}
|
|
167
198
|
/** Get the cluster's load balancer. Undefined if disabled. */
|
|
@@ -317,7 +348,7 @@ export default class EcsCluster extends Construct {
|
|
|
317
348
|
config: typeof serviceProps.alarms === "object" ? serviceProps.alarms : {},
|
|
318
349
|
alarmTopic: this.props.alertsTopic,
|
|
319
350
|
applicationId: this.props.applicationId,
|
|
320
|
-
containerInsightsEnabled: this.
|
|
351
|
+
containerInsightsEnabled: this.containerInsightsEnabled
|
|
321
352
|
});
|
|
322
353
|
if (serviceProps.logAlarms && serviceProps.logAlarms.length > 0) {
|
|
323
354
|
createLogPatternAlarms({
|
|
@@ -385,18 +416,32 @@ export default class EcsCluster extends Construct {
|
|
|
385
416
|
const needsFargate = this.anyServiceUsesFargate();
|
|
386
417
|
// Every service enables execute command; without an OVERRIDE here the
|
|
387
418
|
// exec session output interleaves into the container app log groups
|
|
388
|
-
// (DEFAULT mode).
|
|
389
|
-
|
|
419
|
+
// (DEFAULT mode). Session encryption follows the tier: the shared stack
|
|
420
|
+
// key encrypts the session AND its audit log group (ECS requires the
|
|
421
|
+
// audit group to be CMK-encrypted before it will encrypt the session).
|
|
422
|
+
const encryptionKey = this.encryptionKey;
|
|
423
|
+
const execAuditLogGroup = new LogGroup(this, `${props.clusterName}ExecAuditLogGroup`, {
|
|
424
|
+
retention: DEFAULT_FRAMEWORK_LOG_RETENTION,
|
|
425
|
+
...(encryptionKey !== undefined && {
|
|
426
|
+
encryptionKey: encryptionKey.forLogGroups()
|
|
427
|
+
})
|
|
428
|
+
});
|
|
390
429
|
const cluster = new CdkCluster(this, `${props.clusterName}Cluster`, {
|
|
391
430
|
vpc: props.vpc,
|
|
392
431
|
clusterName: props.clusterName,
|
|
393
|
-
containerInsightsV2:
|
|
432
|
+
containerInsightsV2: this.containerInsightsEnabled
|
|
394
433
|
? ContainerInsights.ENABLED
|
|
395
434
|
: ContainerInsights.DISABLED,
|
|
396
435
|
enableFargateCapacityProviders: needsFargate,
|
|
397
436
|
executeCommandConfiguration: {
|
|
437
|
+
...(encryptionKey !== undefined && { kmsKey: encryptionKey.key }),
|
|
398
438
|
logging: ExecuteCommandLogging.OVERRIDE,
|
|
399
|
-
logConfiguration: {
|
|
439
|
+
logConfiguration: {
|
|
440
|
+
cloudWatchLogGroup: execAuditLogGroup,
|
|
441
|
+
...(encryptionKey !== undefined && {
|
|
442
|
+
cloudWatchEncryptionEnabled: true
|
|
443
|
+
})
|
|
444
|
+
}
|
|
400
445
|
}
|
|
401
446
|
});
|
|
402
447
|
new CfnOutput(this, `${this.outputName}DeployableCluster`, {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { Construct } from "constructs";
|
|
2
2
|
import type { Cluster as CdkCluster } from "aws-cdk-lib/aws-ecs";
|
|
3
|
+
import type { StackEncryptionKey } from "../secrets/stackEncryptionKey.js";
|
|
3
4
|
import type { EcsClusterProps } from "./ecsTypes.js";
|
|
4
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Shared state passed from EcsCluster to extracted helper functions. The
|
|
7
|
+
* tier-owned knobs are resolved once in the constructor and read here as
|
|
8
|
+
* plain values — helpers never consult the tier themselves.
|
|
9
|
+
*/
|
|
5
10
|
export interface EcsConstructContext {
|
|
6
11
|
scope: Construct;
|
|
7
12
|
props: EcsClusterProps;
|
|
@@ -9,4 +14,8 @@ export interface EcsConstructContext {
|
|
|
9
14
|
outputName: string;
|
|
10
15
|
loadBalancerDisabled: boolean;
|
|
11
16
|
directAccessEnabled: boolean;
|
|
17
|
+
/** The stack's shared key when the tier encrypts; undefined otherwise. */
|
|
18
|
+
encryptionKey: StackEncryptionKey | undefined;
|
|
19
|
+
loadBalancerDeletionProtection: boolean;
|
|
20
|
+
loadBalancerAccessLogs: boolean;
|
|
12
21
|
}
|
|
@@ -44,7 +44,9 @@ export function addLoadBalancer(ctx, anyServiceUsesEc2, asgSecurityGroup) {
|
|
|
44
44
|
loadBalancerName: truncatedLoadBalancerName,
|
|
45
45
|
...(loadBalancerSecurityGroup && {
|
|
46
46
|
securityGroup: loadBalancerSecurityGroup
|
|
47
|
-
})
|
|
47
|
+
}),
|
|
48
|
+
deletionProtection: ctx.loadBalancerDeletionProtection,
|
|
49
|
+
accessLogs: ctx.loadBalancerAccessLogs
|
|
48
50
|
});
|
|
49
51
|
new CfnOutput(ctx.scope, `${ctx.outputName}LoadBalancerDnsName`, {
|
|
50
52
|
key: `${ctx.outputName}LoadBalancerDnsName`,
|
|
@@ -148,7 +148,10 @@ export function addContainersToTask(ctx, serviceName, serviceProps, taskDefiniti
|
|
|
148
148
|
// Removal: env-aware wrapper default (D17) — production RETAIN keeps
|
|
149
149
|
// fail-closed rollback evidence; non-production DESTROY avoids orphans.
|
|
150
150
|
const logGroup = new LogGroup(ctx.scope, `${ctx.props.clusterName}${serviceName}LogGroup`, {
|
|
151
|
-
retention: DEFAULT_LOG_RETENTION
|
|
151
|
+
retention: DEFAULT_LOG_RETENTION,
|
|
152
|
+
...(ctx.encryptionKey !== undefined && {
|
|
153
|
+
encryptionKey: ctx.encryptionKey.forLogGroups()
|
|
154
|
+
})
|
|
152
155
|
});
|
|
153
156
|
for (const containerConfig of serviceProps.containers) {
|
|
154
157
|
const image = getContainerImage(ctx, serviceName, containerConfig, serviceProps);
|
|
@@ -16,6 +16,7 @@ import { type Role } from "aws-cdk-lib/aws-iam";
|
|
|
16
16
|
import { type HostedZone as FjallHostedZone } from "../networking/hostedZone.js";
|
|
17
17
|
import { type Certificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
18
18
|
import { type ConnectionSpec } from "../../../utils/connector.js";
|
|
19
|
+
import type { BackupTier } from "../../../utils/backupTierMapping.js";
|
|
19
20
|
import { type RemoteConnectionSpec } from "./ecsRemoteConnections.js";
|
|
20
21
|
import { type SecretImport } from "../secrets/index.js";
|
|
21
22
|
import type { ManagedDomainBinding, ManagedDomainExports } from "../../../utils/domainTypes.js";
|
|
@@ -472,6 +473,20 @@ export interface EcsClusterClusterConfig {
|
|
|
472
473
|
* by the patterns layer (AC26 — `EcsClusterConfig.securityGroup`).
|
|
473
474
|
*/
|
|
474
475
|
securityGroup?: ISecurityGroup;
|
|
476
|
+
/**
|
|
477
|
+
* Deletion protection on the shared load balancer. Default: the app backup
|
|
478
|
+
* tier's `deletionProtection` column, applied only when the stack's
|
|
479
|
+
* environment resolves to production — a dev or staging stack is torn
|
|
480
|
+
* down by design. The destroy pre-flight switches it off before a
|
|
481
|
+
* consented destroy.
|
|
482
|
+
*/
|
|
483
|
+
loadBalancerDeletionProtection?: boolean;
|
|
484
|
+
/**
|
|
485
|
+
* Access logs from the shared load balancer, delivered to the stack's
|
|
486
|
+
* lifecycle-expired access-log bucket under `alb/<load balancer id>/`.
|
|
487
|
+
* Default: the app backup tier's `albAccessLogs` column.
|
|
488
|
+
*/
|
|
489
|
+
loadBalancerAccessLogs?: boolean;
|
|
475
490
|
}
|
|
476
491
|
/**
|
|
477
492
|
* Routing configuration for path/host-based routing on the ALB.
|
|
@@ -749,15 +764,23 @@ export interface EcsClusterProps {
|
|
|
749
764
|
*/
|
|
750
765
|
taskStopWatchdog?: false;
|
|
751
766
|
/**
|
|
752
|
-
* CloudWatch Container Insights
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
*
|
|
758
|
-
*
|
|
767
|
+
* CloudWatch Container Insights. Default: the app backup tier's
|
|
768
|
+
* `containerInsights` column (on at enterprise, off below). Enabling it
|
|
769
|
+
* bills ~$0.30/metric-month of custom `ECS/ContainerInsights` metrics per
|
|
770
|
+
* cluster plus performance-log ingestion. The per-service running-tasks
|
|
771
|
+
* alarm is the one construct consumer of that namespace (`RunningTaskCount`
|
|
772
|
+
* exists nowhere else) and is skipped when insights are off; every other
|
|
773
|
+
* alarm sits on `AWS/ECS` and `Fjall/ECS`. `false` is an explicit,
|
|
774
|
+
* auditable opt-out at enterprise.
|
|
775
|
+
*/
|
|
776
|
+
containerInsights?: boolean;
|
|
777
|
+
/**
|
|
778
|
+
* The owning app's backup tier, which the tier-owned defaults (Container
|
|
779
|
+
* Insights, exec-session and log-group encryption, load-balancer deletion
|
|
780
|
+
* protection and access logs) follow. `ComputeFactory` fills it from the
|
|
781
|
+
* App; pass it only for direct `new EcsCluster(...)` construction.
|
|
759
782
|
*/
|
|
760
|
-
|
|
783
|
+
appBackupTier?: BackupTier;
|
|
761
784
|
}
|
|
762
785
|
/**
|
|
763
786
|
* Data tracked for each service in the cluster.
|
|
@@ -3,6 +3,7 @@ import { type Bucket } from "aws-cdk-lib/aws-s3";
|
|
|
3
3
|
import { PolicyStatement, type IRole } from "aws-cdk-lib/aws-iam";
|
|
4
4
|
import { type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
5
5
|
import type { RetentionDays } from "aws-cdk-lib/aws-logs";
|
|
6
|
+
import { type BackupTier } from "../../../utils/backupTierMapping.js";
|
|
6
7
|
import { type IQueue } from "aws-cdk-lib/aws-sqs";
|
|
7
8
|
import { type ITable } from "aws-cdk-lib/aws-dynamodb";
|
|
8
9
|
import { type Construct } from "constructs";
|
|
@@ -92,8 +93,24 @@ export interface LambdaFunctionProps {
|
|
|
92
93
|
alarms?: LambdaAlarmThresholds | false;
|
|
93
94
|
/** Application ID for alarm tagging. */
|
|
94
95
|
applicationId?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Active X-Ray tracing. Default: the app backup tier's `lambdaTracing`
|
|
98
|
+
* column (on at enterprise).
|
|
99
|
+
*/
|
|
100
|
+
tracing?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* The owning app's backup tier, which the tier-owned defaults (tracing,
|
|
103
|
+
* environment-variable and log-group encryption) follow. `ComputeFactory`
|
|
104
|
+
* fills it from the App; pass it only for direct `new LambdaFunction(...)`
|
|
105
|
+
* construction.
|
|
106
|
+
*/
|
|
107
|
+
appBackupTier?: BackupTier;
|
|
95
108
|
}
|
|
96
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Framework custom-resource handlers are tier-agnostic: the tier-owned
|
|
111
|
+
* knobs are excluded at the type rather than silently ignored.
|
|
112
|
+
*/
|
|
113
|
+
export interface SingletonFunctionProps extends Omit<LambdaFunctionProps, "tracing" | "appBackupTier"> {
|
|
97
114
|
uuid?: string;
|
|
98
115
|
ephemeralStorageSize?: number;
|
|
99
116
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Annotations, CfnOutput, Duration, Stack, Size } from "aws-cdk-lib";
|
|
2
|
-
import { SingletonFunction as singletonFunction, Function, Code, Architecture, FunctionUrlAuthType, StartingPosition, LayerVersion } from "aws-cdk-lib/aws-lambda";
|
|
2
|
+
import { SingletonFunction as singletonFunction, Function, Code, Architecture, FunctionUrlAuthType, StartingPosition, LayerVersion, Tracing } from "aws-cdk-lib/aws-lambda";
|
|
3
3
|
import { FactName } from "aws-cdk-lib/region-info";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -8,6 +8,8 @@ import { SqsEventSource, DynamoEventSource, S3EventSource } from "aws-cdk-lib/aw
|
|
|
8
8
|
import { EventType } from "aws-cdk-lib/aws-s3";
|
|
9
9
|
import { PolicyStatement, Effect } from "aws-cdk-lib/aws-iam";
|
|
10
10
|
import { DEFAULT_FRAMEWORK_LOG_RETENTION, LogGroup } from "../logging/logGroup.js";
|
|
11
|
+
import { tierDefault } from "../../../utils/backupTierMapping.js";
|
|
12
|
+
import { StackEncryptionKey } from "../secrets/stackEncryptionKey.js";
|
|
11
13
|
import { Queue, QueueEncryption } from "aws-cdk-lib/aws-sqs";
|
|
12
14
|
import { SQS_LIMITS } from "../messaging/sqs.js";
|
|
13
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -167,12 +169,25 @@ export class LambdaFunction extends Function {
|
|
|
167
169
|
asyncFailureQueueWired;
|
|
168
170
|
constructor(scope, id, props) {
|
|
169
171
|
validateRuntimeNotDeprecated(props.runtime, id);
|
|
172
|
+
// Both are Fjall props, not CDK ones: `tracing` collides with the CDK
|
|
173
|
+
// enum of the same name and `appBackupTier` is unknown to CDK.
|
|
174
|
+
const { tracing, appBackupTier, ...cdkProps } = props;
|
|
170
175
|
const vpcSubnets = props.vpc
|
|
171
176
|
? { subnetType: resolvePrivateSubnetType(props.vpc) }
|
|
172
177
|
: undefined;
|
|
178
|
+
const tracingEnabled = tracing ?? tierDefault(appBackupTier, "lambdaTracing");
|
|
179
|
+
// Grant-based: Lambda encrypts the environment through a KMS grant the
|
|
180
|
+
// deploying role creates, so the execution role needs no key policy.
|
|
181
|
+
const encryptionKey = tierDefault(appBackupTier, "customerManagedKeys")
|
|
182
|
+
? StackEncryptionKey.of(scope)
|
|
183
|
+
: undefined;
|
|
173
184
|
super(scope, id, {
|
|
174
|
-
...
|
|
185
|
+
...cdkProps,
|
|
175
186
|
vpcSubnets,
|
|
187
|
+
...(tracingEnabled && { tracing: Tracing.ACTIVE }),
|
|
188
|
+
...(encryptionKey !== undefined && {
|
|
189
|
+
environmentEncryption: encryptionKey.key
|
|
190
|
+
}),
|
|
176
191
|
timeout: Duration.seconds(props.timeout ?? LAMBDA_DEFAULT_TIMEOUT_SECONDS),
|
|
177
192
|
memorySize: props.memorySize ?? 128,
|
|
178
193
|
ephemeralStorageSize: props.ephemeralStorageSize
|
|
@@ -181,7 +196,10 @@ export class LambdaFunction extends Function {
|
|
|
181
196
|
description: props.lambdaDescription ?? `${id} Lambda`,
|
|
182
197
|
environment: props.environment,
|
|
183
198
|
logGroup: new LogGroup(scope, `${id}LogGroup`, {
|
|
184
|
-
retention: props.logGroupRetention ?? DEFAULT_FRAMEWORK_LOG_RETENTION
|
|
199
|
+
retention: props.logGroupRetention ?? DEFAULT_FRAMEWORK_LOG_RETENTION,
|
|
200
|
+
...(encryptionKey !== undefined && {
|
|
201
|
+
encryptionKey: encryptionKey.forLogGroups()
|
|
202
|
+
})
|
|
185
203
|
})
|
|
186
204
|
});
|
|
187
205
|
this.asyncFailureQueueProp = props.asyncFailureQueue;
|
|
@@ -155,7 +155,7 @@ export declare const CLICKHOUSE_NATIVE_PORT = 9000;
|
|
|
155
155
|
export declare const CLICKHOUSE_PROMETHEUS_PORT = 9363;
|
|
156
156
|
/** TLS-mode ClickHouse ports.
|
|
157
157
|
* HTTPS replaces 8123; secure native protocol replaces 9000.
|
|
158
|
-
* See
|
|
158
|
+
* See the ClickHouse TLS pattern, § "The contract". */
|
|
159
159
|
export declare const CLICKHOUSE_HTTPS_PORT = 8443;
|
|
160
160
|
export declare const CLICKHOUSE_TCP_SECURE_PORT = 9440;
|
|
161
161
|
/** Mount path inside the ClickHouse container for the materialised TLS cert
|
|
@@ -188,8 +188,8 @@ export declare function clickHouseUserSecretName(userName: string): string;
|
|
|
188
188
|
* Canonical source is `@fjall/util/migration § userPasswordEnvName` — re-exported
|
|
189
189
|
* here so the construct-side import chain stays unchanged while the runner
|
|
190
190
|
* (`webapp/scripts/migration-runner.mjs`) and any future consumer share a single
|
|
191
|
-
* declaration. Coupled values
|
|
192
|
-
*
|
|
191
|
+
* declaration. Coupled values (the shared-source-at-two-occurrences
|
|
192
|
+
* rule). */
|
|
193
193
|
export { userPasswordEnvName } from "@fjall/util/migration";
|
|
194
194
|
/** Env var name carrying the SHA-256 of a user's plaintext password.
|
|
195
195
|
* The container entrypoint wrapper derives this name from the
|
|
@@ -305,8 +305,8 @@ export declare const BACKUP_RETENTION_DAYS = 14;
|
|
|
305
305
|
* wrote can be read back. Dropped on the way in and on the way out; never
|
|
306
306
|
* queried by the application. Canonical source is `@fjall/util/migration`
|
|
307
307
|
* because `@fjall/clickhouse` grants `fjall_maintenance` DROP on exactly
|
|
308
|
-
* this database — coupled values
|
|
309
|
-
*
|
|
308
|
+
* this database — coupled values (the shared-source-at-two-occurrences
|
|
309
|
+
* rule). */
|
|
310
310
|
export { CLICKHOUSE_BACKUP_SCRATCH_DATABASE } from "@fjall/util/migration";
|
|
311
311
|
/** The two scheduled maintenance jobs that authenticate as
|
|
312
312
|
* `fjall_maintenance`. Drives the per-job log-group → metric-filter wiring
|
|
@@ -175,7 +175,7 @@ export const CLICKHOUSE_NATIVE_PORT = 9000;
|
|
|
175
175
|
export const CLICKHOUSE_PROMETHEUS_PORT = 9363;
|
|
176
176
|
/** TLS-mode ClickHouse ports.
|
|
177
177
|
* HTTPS replaces 8123; secure native protocol replaces 9000.
|
|
178
|
-
* See
|
|
178
|
+
* See the ClickHouse TLS pattern, § "The contract". */
|
|
179
179
|
export const CLICKHOUSE_HTTPS_PORT = 8443;
|
|
180
180
|
export const CLICKHOUSE_TCP_SECURE_PORT = 9440;
|
|
181
181
|
/** Mount path inside the ClickHouse container for the materialised TLS cert
|
|
@@ -210,8 +210,8 @@ export function clickHouseUserSecretName(userName) {
|
|
|
210
210
|
* Canonical source is `@fjall/util/migration § userPasswordEnvName` — re-exported
|
|
211
211
|
* here so the construct-side import chain stays unchanged while the runner
|
|
212
212
|
* (`webapp/scripts/migration-runner.mjs`) and any future consumer share a single
|
|
213
|
-
* declaration. Coupled values
|
|
214
|
-
*
|
|
213
|
+
* declaration. Coupled values (the shared-source-at-two-occurrences
|
|
214
|
+
* rule). */
|
|
215
215
|
export { userPasswordEnvName } from "@fjall/util/migration";
|
|
216
216
|
/** Env var name carrying the SHA-256 of a user's plaintext password.
|
|
217
217
|
* The container entrypoint wrapper derives this name from the
|
|
@@ -347,8 +347,8 @@ export const BACKUP_RETENTION_DAYS = 14;
|
|
|
347
347
|
* wrote can be read back. Dropped on the way in and on the way out; never
|
|
348
348
|
* queried by the application. Canonical source is `@fjall/util/migration`
|
|
349
349
|
* because `@fjall/clickhouse` grants `fjall_maintenance` DROP on exactly
|
|
350
|
-
* this database — coupled values
|
|
351
|
-
*
|
|
350
|
+
* this database — coupled values (the shared-source-at-two-occurrences
|
|
351
|
+
* rule). */
|
|
352
352
|
export { CLICKHOUSE_BACKUP_SCRATCH_DATABASE } from "@fjall/util/migration";
|
|
353
353
|
/** The two scheduled maintenance jobs that authenticate as
|
|
354
354
|
* `fjall_maintenance`. Drives the per-job log-group → metric-filter wiring
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
+
import { type BackupTier } from "../../../utils/backupTierMapping.js";
|
|
2
3
|
import { type ITable } from "aws-cdk-lib/aws-dynamodb";
|
|
3
4
|
import { type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
|
|
4
5
|
export type DynamoDBAttributeType = "S" | "N" | "B";
|
|
@@ -24,9 +25,27 @@ export interface DynamoDBTableProps {
|
|
|
24
25
|
timeToLiveAttribute?: string;
|
|
25
26
|
stream?: "NEW_IMAGE" | "OLD_IMAGE" | "NEW_AND_OLD_IMAGES" | "KEYS_ONLY";
|
|
26
27
|
pointInTimeRecovery?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Encryption at rest. Default: the app backup tier's `customerManagedKeys`
|
|
30
|
+
* column — `CUSTOMER_MANAGED` at enterprise, `AWS_MANAGED` otherwise.
|
|
31
|
+
* `CUSTOMER_MANAGED` always encrypts with the stack's shared
|
|
32
|
+
* [[StackEncryptionKey]]; switching a live table's key is an in-place
|
|
33
|
+
* update.
|
|
34
|
+
*/
|
|
27
35
|
encryption?: "AWS_OWNED" | "AWS_MANAGED" | "CUSTOMER_MANAGED";
|
|
36
|
+
/**
|
|
37
|
+
* DynamoDB `DeletionProtectionEnabled`. Default: the app backup tier's
|
|
38
|
+
* `deletionProtection` column (on at resilient and enterprise). The
|
|
39
|
+
* destroy pre-flight switches it off before a consented destroy.
|
|
40
|
+
*/
|
|
28
41
|
deletionProtection?: boolean;
|
|
29
42
|
removalPolicy?: "DESTROY" | "RETAIN" | "SNAPSHOT";
|
|
43
|
+
/**
|
|
44
|
+
* The owning app's backup tier, which the tier-owned defaults (encryption,
|
|
45
|
+
* deletion protection) follow. `DatabaseFactory` fills it from the App;
|
|
46
|
+
* pass it only for direct `new DynamoDBTable(...)` construction.
|
|
47
|
+
*/
|
|
48
|
+
appBackupTier?: BackupTier;
|
|
30
49
|
}
|
|
31
50
|
export declare class DynamoDBTable extends Construct {
|
|
32
51
|
readonly id: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
2
|
import { CfnOutput } from "aws-cdk-lib";
|
|
3
|
+
import { tierDefault } from "../../../utils/backupTierMapping.js";
|
|
3
4
|
import { toRemovalPolicy } from "../../../utils/removalPolicy.js";
|
|
5
|
+
import { StackEncryptionKey } from "../secrets/stackEncryptionKey.js";
|
|
4
6
|
import { Table, AttributeType, BillingMode, StreamViewType, ProjectionType, TableEncryption } from "aws-cdk-lib/aws-dynamodb";
|
|
5
7
|
function toAttributeType(type) {
|
|
6
8
|
switch (type) {
|
|
@@ -64,6 +66,12 @@ export class DynamoDBTable extends Construct {
|
|
|
64
66
|
constructor(scope, id, props) {
|
|
65
67
|
super(scope, id);
|
|
66
68
|
this.id = id;
|
|
69
|
+
const encryption = props.encryption ??
|
|
70
|
+
(tierDefault(props.appBackupTier, "customerManagedKeys")
|
|
71
|
+
? "CUSTOMER_MANAGED"
|
|
72
|
+
: "AWS_MANAGED");
|
|
73
|
+
const deletionProtection = props.deletionProtection ??
|
|
74
|
+
tierDefault(props.appBackupTier, "deletionProtection");
|
|
67
75
|
this.table = new Table(this, `${id}Table`, {
|
|
68
76
|
tableName: props.tableName,
|
|
69
77
|
partitionKey: {
|
|
@@ -83,8 +91,11 @@ export class DynamoDBTable extends Construct {
|
|
|
83
91
|
pointInTimeRecoverySpecification: {
|
|
84
92
|
pointInTimeRecoveryEnabled: props.pointInTimeRecovery ?? true
|
|
85
93
|
},
|
|
86
|
-
encryption: toTableEncryption(
|
|
87
|
-
|
|
94
|
+
encryption: toTableEncryption(encryption),
|
|
95
|
+
...(encryption === "CUSTOMER_MANAGED" && {
|
|
96
|
+
encryptionKey: StackEncryptionKey.of(this).key
|
|
97
|
+
}),
|
|
98
|
+
deletionProtection,
|
|
88
99
|
removalPolicy: toRemovalPolicy(props.removalPolicy),
|
|
89
100
|
timeToLiveAttribute: props.timeToLiveAttribute
|
|
90
101
|
});
|
|
@@ -3,6 +3,7 @@ import { Connections, type IConnectable, type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
|
3
3
|
import { DatabaseCluster, type CfnDBCluster, type IClusterEngine } from "aws-cdk-lib/aws-rds";
|
|
4
4
|
import { Construct } from "constructs";
|
|
5
5
|
import { Secret } from "../secrets/index.js";
|
|
6
|
+
import { type BackupTier } from "../../../utils/backupTierMapping.js";
|
|
6
7
|
import type { ITopic } from "aws-cdk-lib/aws-sns";
|
|
7
8
|
import { type RdsAlarmThresholds } from "../monitoring/index.js";
|
|
8
9
|
import { type EngineConfig, type ProxyConfig, type CredentialsConfig, type AuroraEncryptionConfig, type AuroraWriterConfig, type AuroraReadersConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
|
|
@@ -40,7 +41,17 @@ interface RdsProps {
|
|
|
40
41
|
proxy?: ProxyConfig | false;
|
|
41
42
|
credentials?: CredentialsConfig;
|
|
42
43
|
encryption?: AuroraEncryptionConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Automated backup retention in days. Defaults to the app backup tier's
|
|
46
|
+
* column (`tierDefault(appBackupTier, "rdsBackupRetentionDays")`).
|
|
47
|
+
*/
|
|
43
48
|
backupRetention?: number;
|
|
49
|
+
/**
|
|
50
|
+
* The owning app's backup tier (`App.getApp({ backup: { tier } })`), which
|
|
51
|
+
* the retention default follows. `DatabaseFactory` fills it from the App;
|
|
52
|
+
* pass it only for direct `new RdsAurora(...)` construction.
|
|
53
|
+
*/
|
|
54
|
+
appBackupTier?: BackupTier;
|
|
44
55
|
monitoringInterval?: Duration;
|
|
45
56
|
preferredMaintenanceWindow?: string;
|
|
46
57
|
port?: number;
|
|
@@ -6,8 +6,9 @@ import { Construct } from "constructs";
|
|
|
6
6
|
import { SecurityGroup } from "../networking/securityGroup.js";
|
|
7
7
|
import { Secret } from "../secrets/index.js";
|
|
8
8
|
import { ResourceNaming } from "../../../utils/resourceNaming.js";
|
|
9
|
+
import { tierDefault } from "../../../utils/backupTierMapping.js";
|
|
9
10
|
import { addProxyCfnOutput } from "./rdsProxyOutput.js";
|
|
10
|
-
import { getDatabaseInsightsRetention } from "./index.js";
|
|
11
|
+
import { getCdkDatabaseInsightsMode, getDatabaseInsightsRetention } from "./index.js";
|
|
11
12
|
import { RDS_DEFAULTS, SERVERLESS_V2_AUTO_PAUSE_MIN_SECONDS, SERVERLESS_V2_AUTO_PAUSE_MAX_SECONDS, MIN_AUTO_PAUSE_POSTGRES_VERSION } from "./rdsDefaults.js";
|
|
12
13
|
import { createRdsAlarms } from "../monitoring/index.js";
|
|
13
14
|
import { DEFAULT_POSTGRES_ENGINE_CONFIG, resolveDatabaseInsights, resolveStorageEncryptionKey, resolvePerformanceInsightsKey, addMultiUserSecretRotation, warnIfSnapshotUsernameAssumed } from "./rdsHelpers.js";
|
|
@@ -138,8 +139,26 @@ export class RdsAurora extends Construct {
|
|
|
138
139
|
const writerConfig = props.writer ?? {};
|
|
139
140
|
const writerPI = writerConfig.enableDatabaseInsights ?? piEnabled;
|
|
140
141
|
const writerSuffix = writerConfig.identifierSuffix;
|
|
141
|
-
|
|
142
|
+
// The tier owns the Database Insights mode; an explicit `mode` wins.
|
|
143
|
+
const diMode = piConfig?.mode ??
|
|
144
|
+
tierDefault(props.appBackupTier, "databaseInsightsMode");
|
|
142
145
|
const performanceInsightsRetention = getDatabaseInsightsRetention(diMode);
|
|
146
|
+
// Advanced mode is a cluster-level setting that CDK validates against
|
|
147
|
+
// every instance: the cluster must carry Performance Insights with the
|
|
148
|
+
// same 15-month retention and key the instances do, or synth throws a
|
|
149
|
+
// retention mismatch. Emitted only when it applies, so a standard
|
|
150
|
+
// template stays byte-identical.
|
|
151
|
+
const advancedInsights = piEnabled && diMode === "advanced";
|
|
152
|
+
const clusterInsightsProps = advancedInsights
|
|
153
|
+
? {
|
|
154
|
+
enablePerformanceInsights: true,
|
|
155
|
+
performanceInsightRetention: performanceInsightsRetention,
|
|
156
|
+
...(performanceInsightsKey && {
|
|
157
|
+
performanceInsightEncryptionKey: performanceInsightsKey
|
|
158
|
+
}),
|
|
159
|
+
databaseInsightsMode: getCdkDatabaseInsightsMode(diMode)
|
|
160
|
+
}
|
|
161
|
+
: {};
|
|
143
162
|
const writer = ClusterInstance.serverlessV2(`${this.databaseNameValue}Writer`, {
|
|
144
163
|
enablePerformanceInsights: writerPI,
|
|
145
164
|
performanceInsightEncryptionKey: writerPI
|
|
@@ -170,7 +189,8 @@ export class RdsAurora extends Construct {
|
|
|
170
189
|
? { subnetType: SubnetType.PUBLIC }
|
|
171
190
|
: { subnetType: SubnetType.PRIVATE_WITH_EGRESS };
|
|
172
191
|
this.backupRetentionDaysValue =
|
|
173
|
-
props.backupRetention ??
|
|
192
|
+
props.backupRetention ??
|
|
193
|
+
tierDefault(props.appBackupTier, "rdsBackupRetentionDays");
|
|
174
194
|
// Common props shared across all cluster creation paths
|
|
175
195
|
const baseClusterProps = {
|
|
176
196
|
vpc: props.vpc,
|
|
@@ -194,6 +214,7 @@ export class RdsAurora extends Construct {
|
|
|
194
214
|
removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT,
|
|
195
215
|
deletionProtection: props.deletionProtection ?? true,
|
|
196
216
|
iamAuthentication: true,
|
|
217
|
+
...clusterInsightsProps,
|
|
197
218
|
...(props.serverlessV2MinCapacity !== undefined && {
|
|
198
219
|
serverlessV2MinCapacity: props.serverlessV2MinCapacity
|
|
199
220
|
}),
|
|
@@ -6,6 +6,7 @@ import { type ITopic } from "aws-cdk-lib/aws-sns";
|
|
|
6
6
|
import { type Secret } from "../secrets/index.js";
|
|
7
7
|
import { type RdsAlarmThresholds } from "../monitoring/index.js";
|
|
8
8
|
import { type EngineConfig, type ProxyConfig, type CredentialsConfig, type AuroraEncryptionConfig, type AuroraWriterConfig, type AuroraReadersConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
|
|
9
|
+
import { type BackupTier } from "../../../utils/backupTierMapping.js";
|
|
9
10
|
interface RdsAuroraGlobalProps {
|
|
10
11
|
vpc: IVpc;
|
|
11
12
|
databaseName: string;
|
|
@@ -37,8 +38,17 @@ interface RdsAuroraGlobalProps {
|
|
|
37
38
|
credentials?: CredentialsConfig;
|
|
38
39
|
/** Encryption configuration */
|
|
39
40
|
encryption?: AuroraEncryptionConfig;
|
|
40
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Backup retention in days. Defaults to the app backup tier's column
|
|
43
|
+
* (`tierDefault(appBackupTier, "rdsBackupRetentionDays")`) on every
|
|
44
|
+
* regional cluster.
|
|
45
|
+
*/
|
|
41
46
|
backupRetention?: number;
|
|
47
|
+
/**
|
|
48
|
+
* The owning app's backup tier, forwarded to each regional `RdsAurora`.
|
|
49
|
+
* `DatabaseFactory` fills it from the App.
|
|
50
|
+
*/
|
|
51
|
+
appBackupTier?: BackupTier;
|
|
42
52
|
/** CloudWatch monitoring interval. Default: 1 minute */
|
|
43
53
|
monitoringInterval?: Duration;
|
|
44
54
|
/** Preferred maintenance window. Default: "Sat:12:30-Sat:20:30" */
|
|
@@ -83,6 +83,7 @@ export class RdsAuroraGlobal extends Construct {
|
|
|
83
83
|
encryption: this.props.encryption,
|
|
84
84
|
// Operational configuration
|
|
85
85
|
backupRetention: this.props.backupRetention,
|
|
86
|
+
appBackupTier: this.props.appBackupTier,
|
|
86
87
|
monitoringInterval: this.props.monitoringInterval,
|
|
87
88
|
preferredMaintenanceWindow: this.props.preferredMaintenanceWindow,
|
|
88
89
|
port: this.props.port,
|
|
@@ -4,8 +4,6 @@ export declare const RDS_DEFAULTS: Readonly<{
|
|
|
4
4
|
readonly PREFERRED_MAINTENANCE_WINDOW: "Sat:12:30-Sat:20:30";
|
|
5
5
|
/** 1 minute — balances monitoring granularity against CloudWatch costs */
|
|
6
6
|
readonly MONITORING_INTERVAL: Duration;
|
|
7
|
-
/** Default backup retention in days — applied uniformly across Aurora and RDS Instance */
|
|
8
|
-
readonly BACKUP_RETENTION_DEFAULT_DAYS: 14;
|
|
9
7
|
/** Default instance type — primary and read-replica must stay in lockstep */
|
|
10
8
|
readonly DEFAULT_INSTANCE_TYPE: "t4g.large";
|
|
11
9
|
/** Default storage autoscaling ceiling (GiB) — applied to primary and replica */
|
|
@@ -4,8 +4,6 @@ export const RDS_DEFAULTS = Object.freeze({
|
|
|
4
4
|
PREFERRED_MAINTENANCE_WINDOW: "Sat:12:30-Sat:20:30",
|
|
5
5
|
/** 1 minute — balances monitoring granularity against CloudWatch costs */
|
|
6
6
|
MONITORING_INTERVAL: Duration.minutes(1),
|
|
7
|
-
/** Default backup retention in days — applied uniformly across Aurora and RDS Instance */
|
|
8
|
-
BACKUP_RETENTION_DEFAULT_DAYS: 14,
|
|
9
7
|
/** Default instance type — primary and read-replica must stay in lockstep */
|
|
10
8
|
DEFAULT_INSTANCE_TYPE: "t4g.large",
|
|
11
9
|
/** Default storage autoscaling ceiling (GiB) — applied to primary and replica */
|
|
@@ -7,6 +7,7 @@ import { SecurityGroup } from "../networking/securityGroup.js";
|
|
|
7
7
|
import { Secret } from "../secrets/index.js";
|
|
8
8
|
import { type StackBuilder } from "../base/awsStack.js";
|
|
9
9
|
import { type EngineConfig, type ProxyConfig, type ReadReplicaConfig, type CredentialsConfig, type EncryptionConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
|
|
10
|
+
import { type BackupTier } from "../../../utils/backupTierMapping.js";
|
|
10
11
|
import type { ITopic } from "aws-cdk-lib/aws-sns";
|
|
11
12
|
import { type RdsAlarmThresholds } from "../monitoring/index.js";
|
|
12
13
|
interface RdsProps {
|
|
@@ -17,7 +18,17 @@ interface RdsProps {
|
|
|
17
18
|
instanceType?: string;
|
|
18
19
|
maxAllocatedStorage?: number;
|
|
19
20
|
allocatedStorage?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Automated backup retention. Defaults to the app backup tier's column
|
|
23
|
+
* (`tierDefault(appBackupTier, "rdsBackupRetentionDays")`).
|
|
24
|
+
*/
|
|
20
25
|
backupRetention?: Duration;
|
|
26
|
+
/**
|
|
27
|
+
* The owning app's backup tier (`App.getApp({ backup: { tier } })`), which
|
|
28
|
+
* the retention default follows. `DatabaseFactory` fills it from the App;
|
|
29
|
+
* pass it only for direct `new RdsInstance(...)` construction.
|
|
30
|
+
*/
|
|
31
|
+
appBackupTier?: BackupTier;
|
|
21
32
|
preferredBackupWindow?: string;
|
|
22
33
|
clusterIdentifier?: string;
|
|
23
34
|
monitoringInterval?: Duration;
|