@fjall/components-infrastructure 2.24.0 → 2.25.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/dist/lib/resources/aws/database/rdsAurora.d.ts +1 -0
- package/dist/lib/resources/aws/database/rdsAurora.js +34 -6
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +1 -1
- 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 +1 -0
- package/dist/lib/resources/aws/database/rdsInstance.js +24 -3
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Duration, RemovalPolicy } from "aws-cdk-lib";
|
|
1
|
+
import { Annotations, Duration, RemovalPolicy } from "aws-cdk-lib";
|
|
2
|
+
import { ENGINE_DEFAULT_DATABASE_PORTS } from "@fjall/generator";
|
|
2
3
|
import { Connections, Peer, Port, SubnetType } from "aws-cdk-lib/aws-ec2";
|
|
3
4
|
import { AuroraPostgresEngineVersion, CaCertificate, ClusterInstance, Credentials, DatabaseCluster, DatabaseClusterFromSnapshot, DatabaseClusterEngine, DatabaseProxy, ParameterGroup, ProxyTarget, SnapshotCredentials } from "aws-cdk-lib/aws-rds";
|
|
4
5
|
import { Construct } from "constructs";
|
|
@@ -14,6 +15,7 @@ export class RdsAurora extends Construct {
|
|
|
14
15
|
connections;
|
|
15
16
|
constructId;
|
|
16
17
|
port;
|
|
18
|
+
clientPort;
|
|
17
19
|
engineConfig;
|
|
18
20
|
databaseCluster;
|
|
19
21
|
databaseProxy;
|
|
@@ -23,10 +25,16 @@ export class RdsAurora extends Construct {
|
|
|
23
25
|
constructor(scope, id, props) {
|
|
24
26
|
super(scope, id);
|
|
25
27
|
this.constructId = id;
|
|
26
|
-
this.port = props.port ?? RDS_DEFAULTS.DEFAULT_PORT;
|
|
27
28
|
this.databaseNameValue = props.databaseName ?? id;
|
|
28
29
|
// PostgreSQL fallback for direct usage - ensure engine and engineConfig match
|
|
29
30
|
this.engineConfig = props.engineConfig ?? DEFAULT_POSTGRES_ENGINE_CONFIG;
|
|
31
|
+
const engineDefaultPort = ENGINE_DEFAULT_DATABASE_PORTS[this.engineConfig.family];
|
|
32
|
+
this.port = props.port ?? engineDefaultPort;
|
|
33
|
+
// RDS Proxy listens exclusively on the engine-default port (CreateDBProxy
|
|
34
|
+
// has no port parameter), so the client-facing surface must advertise it
|
|
35
|
+
// whenever a proxy fronts the cluster.
|
|
36
|
+
const proxyEnabled = props.proxy !== undefined && props.proxy !== false;
|
|
37
|
+
this.clientPort = proxyEnabled ? engineDefaultPort : this.port;
|
|
30
38
|
const { piEnabled, piConfig } = resolveDatabaseInsights(props.databaseInsights);
|
|
31
39
|
// Username priority: snapshotUsername > credentials.username > engine default
|
|
32
40
|
const username = props.snapshotIdentifier && props.snapshotUsername
|
|
@@ -158,7 +166,6 @@ export class RdsAurora extends Construct {
|
|
|
158
166
|
this.cfnCluster.masterUserPassword = undefined;
|
|
159
167
|
this.cfnCluster.databaseName = undefined;
|
|
160
168
|
}
|
|
161
|
-
const proxyEnabled = props.proxy !== undefined && props.proxy !== false;
|
|
162
169
|
if (proxyEnabled) {
|
|
163
170
|
this.addProxy(props, clusterSecurityGroup);
|
|
164
171
|
}
|
|
@@ -214,18 +221,26 @@ export class RdsAurora extends Construct {
|
|
|
214
221
|
});
|
|
215
222
|
});
|
|
216
223
|
}
|
|
217
|
-
addProxy(props,
|
|
224
|
+
addProxy(props, clusterSecurityGroup) {
|
|
218
225
|
if (!props.proxy)
|
|
219
226
|
return;
|
|
220
227
|
const proxyConfig = props.proxy;
|
|
221
228
|
const vpcSubnets = proxyConfig.vpcSubnets ?? {
|
|
222
229
|
subnetType: SubnetType.PRIVATE_WITH_EGRESS
|
|
223
230
|
};
|
|
231
|
+
const proxySecurityGroup = new SecurityGroup(this, `${this.databaseNameValue}ProxySecurityGroup`, {
|
|
232
|
+
vpc: props.vpc,
|
|
233
|
+
description: `Security group for RDS Proxy ${this.databaseNameValue}`
|
|
234
|
+
});
|
|
235
|
+
clusterSecurityGroup.addIngressRule(proxySecurityGroup, Port.tcp(this.port), "Allow RDS Proxy to connect to Aurora cluster");
|
|
236
|
+
if (props.allowVpcAccess) {
|
|
237
|
+
proxySecurityGroup.addIngressRule(Peer.ipv4(props.vpc.vpcCidrBlock), Port.tcp(this.clientPort), "Allow access from VPC CIDR");
|
|
238
|
+
}
|
|
224
239
|
this.databaseProxy = new DatabaseProxy(this, `${this.databaseNameValue}DatabaseProxy`, {
|
|
225
240
|
dbProxyName: ResourceNaming.proxyName(this.constructId),
|
|
226
241
|
proxyTarget: ProxyTarget.fromCluster(this.databaseCluster),
|
|
227
242
|
secrets: [this.databaseCredentials.secret],
|
|
228
|
-
securityGroups: [
|
|
243
|
+
securityGroups: [proxySecurityGroup],
|
|
229
244
|
vpc: props.vpc,
|
|
230
245
|
vpcSubnets,
|
|
231
246
|
requireTLS: proxyConfig.requireTLS ?? true,
|
|
@@ -235,6 +250,19 @@ export class RdsAurora extends Construct {
|
|
|
235
250
|
maxConnectionsPercent: proxyConfig.maxConnections,
|
|
236
251
|
maxIdleConnectionsPercent: proxyConfig.maxIdleConnections
|
|
237
252
|
});
|
|
253
|
+
// The proxy is now the client-facing surface: grantConnect /
|
|
254
|
+
// allowDefaultPortFrom must open the PROXY security group on the proxy's
|
|
255
|
+
// fixed engine-default listener port, not the cluster SG on the DB port.
|
|
256
|
+
this.connections = new Connections({
|
|
257
|
+
securityGroups: [proxySecurityGroup],
|
|
258
|
+
defaultPort: Port.tcp(this.clientPort)
|
|
259
|
+
});
|
|
260
|
+
if (this.port !== this.clientPort) {
|
|
261
|
+
Annotations.of(this).addWarning(`Database '${this.databaseNameValue}' listens on port ${this.port}, but its ` +
|
|
262
|
+
`RDS Proxy accepts client connections only on ${this.clientPort} (the engine ` +
|
|
263
|
+
`default — AWS does not allow configuring the proxy listener port). Fjall ` +
|
|
264
|
+
`advertises ${this.clientPort}; direct-to-database access uses ${this.port}.`);
|
|
265
|
+
}
|
|
238
266
|
addProxyCfnOutput(this, this.constructId, this.databaseNameValue, this.databaseProxy);
|
|
239
267
|
}
|
|
240
268
|
addSecretRotation(props) {
|
|
@@ -257,7 +285,7 @@ export class RdsAurora extends Construct {
|
|
|
257
285
|
return this.databaseCluster.clusterEndpoint.hostname;
|
|
258
286
|
}
|
|
259
287
|
getHostPort() {
|
|
260
|
-
return String(this.
|
|
288
|
+
return String(this.clientPort);
|
|
261
289
|
}
|
|
262
290
|
getCredentials() {
|
|
263
291
|
return this.databaseCredentials;
|
|
@@ -43,7 +43,7 @@ interface RdsAuroraGlobalProps {
|
|
|
43
43
|
monitoringInterval?: Duration;
|
|
44
44
|
/** Preferred maintenance window. Default: "Sat:12:30-Sat:20:30" */
|
|
45
45
|
preferredMaintenanceWindow?: string;
|
|
46
|
-
/** Database port. Default:
|
|
46
|
+
/** Database port. Default: engine default (5432 postgresql / 3306 mysql) */
|
|
47
47
|
port?: number;
|
|
48
48
|
databaseInsights?: DatabaseInsightsConfig | false;
|
|
49
49
|
deletionProtection?: boolean;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Duration } from "aws-cdk-lib";
|
|
2
2
|
export declare const RDS_DEFAULTS: Readonly<{
|
|
3
|
-
/** Default database port: FJALL on phone keypad */
|
|
4
|
-
readonly DEFAULT_PORT: 35255;
|
|
5
3
|
/** Saturday window in UTC — minimises weekday impact for scheduled maintenance */
|
|
6
4
|
readonly PREFERRED_MAINTENANCE_WINDOW: "Sat:12:30-Sat:20:30";
|
|
7
5
|
/** 1 minute — balances monitoring granularity against CloudWatch costs */
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Duration } from "aws-cdk-lib";
|
|
2
2
|
export const RDS_DEFAULTS = Object.freeze({
|
|
3
|
-
/** Default database port: FJALL on phone keypad */
|
|
4
|
-
DEFAULT_PORT: 35255,
|
|
5
3
|
/** Saturday window in UTC — minimises weekday impact for scheduled maintenance */
|
|
6
4
|
PREFERRED_MAINTENANCE_WINDOW: "Sat:12:30-Sat:20:30",
|
|
7
5
|
/** 1 minute — balances monitoring granularity against CloudWatch costs */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Duration, RemovalPolicy } from "aws-cdk-lib";
|
|
1
|
+
import { Annotations, Duration, RemovalPolicy } from "aws-cdk-lib";
|
|
2
|
+
import { ENGINE_DEFAULT_DATABASE_PORTS } from "@fjall/generator";
|
|
2
3
|
import { Connections, InstanceType, Port, SubnetType } from "aws-cdk-lib/aws-ec2";
|
|
3
4
|
import { CaCertificate, Credentials, DatabaseInstance, DatabaseInstanceFromSnapshot, DatabaseInstanceEngine, DatabaseInstanceReadReplica, DatabaseProxy, ParameterGroup, PostgresEngineVersion, ProxyTarget, SnapshotCredentials, StorageType } from "aws-cdk-lib/aws-rds";
|
|
4
5
|
import { Runtime } from "aws-cdk-lib/aws-lambda";
|
|
@@ -19,6 +20,7 @@ export class RdsInstance extends Construct {
|
|
|
19
20
|
databaseSecurityGroup;
|
|
20
21
|
vpc;
|
|
21
22
|
port;
|
|
23
|
+
clientPort;
|
|
22
24
|
engineConfig;
|
|
23
25
|
databaseCredentials;
|
|
24
26
|
database;
|
|
@@ -31,11 +33,17 @@ export class RdsInstance extends Construct {
|
|
|
31
33
|
constructor(scope, id, props) {
|
|
32
34
|
super(scope, id);
|
|
33
35
|
this.constructId = id;
|
|
34
|
-
this.port = props.port ?? RDS_DEFAULTS.DEFAULT_PORT;
|
|
35
36
|
this.vpc = props.vpc;
|
|
36
37
|
this.databaseNameValue = props.databaseName ?? id.replace("Rds", "");
|
|
37
38
|
// PostgreSQL fallback for direct usage - ensure engine and engineConfig match
|
|
38
39
|
this.engineConfig = props.engineConfig ?? DEFAULT_POSTGRES_ENGINE_CONFIG;
|
|
40
|
+
const engineDefaultPort = ENGINE_DEFAULT_DATABASE_PORTS[this.engineConfig.family];
|
|
41
|
+
this.port = props.port ?? engineDefaultPort;
|
|
42
|
+
// RDS Proxy listens exclusively on the engine-default port (CreateDBProxy
|
|
43
|
+
// has no port parameter), so the client-facing surface must advertise it
|
|
44
|
+
// whenever a proxy fronts the database.
|
|
45
|
+
const proxyEnabled = props.proxy !== undefined && props.proxy !== false;
|
|
46
|
+
this.clientPort = proxyEnabled ? engineDefaultPort : this.port;
|
|
39
47
|
this.addDatabase(props);
|
|
40
48
|
// Secret rotation enabled by default (opt-out with secretRotation: false)
|
|
41
49
|
const secretRotationDisabled = props.credentials?.secretRotation === false;
|
|
@@ -196,6 +204,19 @@ export class RdsInstance extends Construct {
|
|
|
196
204
|
maxConnectionsPercent: proxyConfig.maxConnections,
|
|
197
205
|
maxIdleConnectionsPercent: proxyConfig.maxIdleConnections
|
|
198
206
|
});
|
|
207
|
+
// The proxy is now the client-facing surface: grantConnect /
|
|
208
|
+
// allowDefaultPortFrom must open the PROXY security group on the proxy's
|
|
209
|
+
// fixed engine-default listener port, not the database SG on the DB port.
|
|
210
|
+
this.connections = new Connections({
|
|
211
|
+
securityGroups: [this.databaseProxySecurityGroup],
|
|
212
|
+
defaultPort: Port.tcp(this.clientPort)
|
|
213
|
+
});
|
|
214
|
+
if (this.port !== this.clientPort) {
|
|
215
|
+
Annotations.of(this).addWarning(`Database '${this.databaseNameValue}' listens on port ${this.port}, but its ` +
|
|
216
|
+
`RDS Proxy accepts client connections only on ${this.clientPort} (the engine ` +
|
|
217
|
+
`default — AWS does not allow configuring the proxy listener port). Fjall ` +
|
|
218
|
+
`advertises ${this.clientPort}; direct-to-database access uses ${this.port}.`);
|
|
219
|
+
}
|
|
199
220
|
addProxyCfnOutput(this, this.constructId, this.databaseNameValue, this.databaseProxy);
|
|
200
221
|
}
|
|
201
222
|
addReadReplica(props) {
|
|
@@ -312,7 +333,7 @@ exports.handler = async (event) => {
|
|
|
312
333
|
}
|
|
313
334
|
}
|
|
314
335
|
getHostPort() {
|
|
315
|
-
return String(this.
|
|
336
|
+
return String(this.clientPort);
|
|
316
337
|
}
|
|
317
338
|
getCredentials() {
|
|
318
339
|
return this.databaseCredentials;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
67
|
-
"@fjall/generator": "^2.
|
|
68
|
-
"@fjall/util": "^2.
|
|
67
|
+
"@fjall/generator": "^2.25.0",
|
|
68
|
+
"@fjall/util": "^2.25.0",
|
|
69
69
|
"constructs": "^10.6.0"
|
|
70
70
|
},
|
|
71
71
|
"overrides": {
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"engines": {
|
|
80
80
|
"node": ">=18.0.0"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "7c1a329184064aefa557c2c09de0965c4f8cd4fb"
|
|
83
83
|
}
|