@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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { CfnOutput, Duration } from "aws-cdk-lib";
|
|
3
|
+
import { PrivateDnsNamespace, DnsRecordType } from "aws-cdk-lib/aws-servicediscovery";
|
|
4
|
+
import { env } from "../../../utils/env.js";
|
|
5
|
+
import { toRemovalPolicy } from "../../../utils/removalPolicy.js";
|
|
6
|
+
export class ServiceDiscoveryNamespace extends Construct {
|
|
7
|
+
id;
|
|
8
|
+
#namespace;
|
|
9
|
+
#services = new Map();
|
|
10
|
+
constructor(scope, id, props) {
|
|
11
|
+
super(scope, id);
|
|
12
|
+
this.id = id;
|
|
13
|
+
const description = props.description ??
|
|
14
|
+
`ServiceDiscovery ${props.name} — Fjall private DNS namespace`;
|
|
15
|
+
const removalPolicyValue = props.removalPolicy ?? env({ default: "DESTROY", production: "RETAIN" });
|
|
16
|
+
const namespace = new PrivateDnsNamespace(this, `${id}Namespace`, {
|
|
17
|
+
vpc: props.vpc,
|
|
18
|
+
name: props.name,
|
|
19
|
+
description
|
|
20
|
+
});
|
|
21
|
+
this.#namespace = namespace;
|
|
22
|
+
namespace.applyRemovalPolicy(toRemovalPolicy(removalPolicyValue));
|
|
23
|
+
new CfnOutput(this, `${id}NamespaceArn`, {
|
|
24
|
+
key: `${id}NamespaceArn`,
|
|
25
|
+
value: namespace.namespaceArn,
|
|
26
|
+
description: `Cloud Map private DNS namespace ARN for ${id}`
|
|
27
|
+
});
|
|
28
|
+
new CfnOutput(this, `${id}NamespaceName`, {
|
|
29
|
+
key: `${id}NamespaceName`,
|
|
30
|
+
value: namespace.namespaceName,
|
|
31
|
+
description: `Cloud Map private DNS namespace name for ${id}`
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the underlying CDK private DNS namespace as the `IPrivateDnsNamespace`
|
|
36
|
+
* interface. Per D18(a), the public surface is the interface, never the
|
|
37
|
+
* concrete `PrivateDnsNamespace` class.
|
|
38
|
+
*/
|
|
39
|
+
getNamespace() {
|
|
40
|
+
return this.#namespace;
|
|
41
|
+
}
|
|
42
|
+
getNamespaceArn() {
|
|
43
|
+
return this.#namespace.namespaceArn;
|
|
44
|
+
}
|
|
45
|
+
getNamespaceName() {
|
|
46
|
+
return this.#namespace.namespaceName;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Register a Cloud Map service inside this namespace. Creates an
|
|
50
|
+
* `AWS::ServiceDiscovery::Service` resource via the underlying CDK
|
|
51
|
+
* `PrivateDnsNamespace.createService(...)` with Fjall description discipline
|
|
52
|
+
* applied. Internal-only per D7(d) — Fjall resources call this from inside
|
|
53
|
+
* their construct bodies; user code never invokes it directly.
|
|
54
|
+
*
|
|
55
|
+
* Throws on duplicate registration: a single namespace cannot host two
|
|
56
|
+
* services with the same DNS name. Caught at synth time, not deploy time.
|
|
57
|
+
*/
|
|
58
|
+
registerService(props) {
|
|
59
|
+
if (this.#services.has(props.name)) {
|
|
60
|
+
throw new Error(`ServiceDiscoveryNamespace '${this.#namespace.namespaceName}': ` +
|
|
61
|
+
`service '${props.name}' is already registered. Each service name ` +
|
|
62
|
+
`must be unique within a namespace.`);
|
|
63
|
+
}
|
|
64
|
+
const description = props.description ?? `Fjall internal service: ${props.name}`;
|
|
65
|
+
const service = this.#namespace.createService(`Service-${props.name}`, {
|
|
66
|
+
name: props.name,
|
|
67
|
+
description,
|
|
68
|
+
dnsTtl: props.dnsTtl ?? Duration.seconds(60),
|
|
69
|
+
dnsRecordType: props.dnsRecordType === "SRV" ? DnsRecordType.SRV : DnsRecordType.A
|
|
70
|
+
});
|
|
71
|
+
this.#services.set(props.name, service);
|
|
72
|
+
return service;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* True if a service with this name has been registered in the namespace.
|
|
76
|
+
* Cheap registry lookup; does NOT consult AWS — only counts services
|
|
77
|
+
* registered via `registerService(...)` on this construct.
|
|
78
|
+
*/
|
|
79
|
+
hasService(name) {
|
|
80
|
+
return this.#services.has(name);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build the FQDN for a previously-registered service:
|
|
84
|
+
* `<serviceName>.<namespaceName>` (e.g. `clickhouse.acme.local`). Throws if
|
|
85
|
+
* the service has not been registered — prevents typos that would silently
|
|
86
|
+
* resolve to NXDOMAIN at runtime.
|
|
87
|
+
*/
|
|
88
|
+
getEndpoint(serviceName) {
|
|
89
|
+
if (!this.#services.has(serviceName)) {
|
|
90
|
+
throw new Error(`ServiceDiscoveryNamespace '${this.#namespace.namespaceName}': ` +
|
|
91
|
+
`service '${serviceName}' has not been registered. Call ` +
|
|
92
|
+
`registerService({ name: '${serviceName}' }) before resolving its endpoint.`);
|
|
93
|
+
}
|
|
94
|
+
return `${serviceName}.${this.#namespace.namespaceName}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { type Construct } from "constructs";
|
|
2
2
|
import * as ec2 from "aws-cdk-lib/aws-ec2";
|
|
3
3
|
import { type StackBuilder } from "../base/awsStack.js";
|
|
4
|
+
export declare const FLOW_LOG_TRAFFIC_TYPES: readonly ["ALL", "ACCEPT", "REJECT"];
|
|
5
|
+
export type FlowLogTrafficType = (typeof FLOW_LOG_TRAFFIC_TYPES)[number];
|
|
6
|
+
export declare const DEFAULT_MAX_AZS = 3;
|
|
4
7
|
export interface VpcFlowLogConfig {
|
|
5
8
|
destination?: "cloudwatch" | "s3";
|
|
6
9
|
retentionDays?: number;
|
|
7
|
-
trafficType?:
|
|
10
|
+
trafficType?: FlowLogTrafficType;
|
|
8
11
|
}
|
|
9
12
|
export interface VpcNatConfig {
|
|
10
13
|
count?: number;
|
|
@@ -3,13 +3,16 @@ import * as ec2 from "aws-cdk-lib/aws-ec2";
|
|
|
3
3
|
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
4
4
|
import { LogGroup } from "../logging/logGroup.js";
|
|
5
5
|
import { S3Bucket } from "../storage/index.js";
|
|
6
|
+
export const FLOW_LOG_TRAFFIC_TYPES = ["ALL", "ACCEPT", "REJECT"];
|
|
7
|
+
// Read at two sites (resources-layer constructor default + patterns-layer natGateways guard) that must agree.
|
|
8
|
+
export const DEFAULT_MAX_AZS = 3;
|
|
6
9
|
export class Vpc extends ec2.Vpc {
|
|
7
10
|
gatewayEndpoints = [];
|
|
8
11
|
interfaceEndpoints = [];
|
|
9
12
|
hasNatGateways;
|
|
10
13
|
constructor(scope, id, props) {
|
|
11
14
|
const { maxAzs: maxAzsFromProps, vpcName: explicitName, ...restProps } = props ?? {};
|
|
12
|
-
const maxAzs = maxAzsFromProps ??
|
|
15
|
+
const maxAzs = maxAzsFromProps ?? DEFAULT_MAX_AZS;
|
|
13
16
|
const natGateways = Vpc.resolveNatGateways(props);
|
|
14
17
|
const vpcName = explicitName ?? id;
|
|
15
18
|
super(scope, `Vpc${id}`, {
|
|
@@ -60,9 +60,27 @@ export class VpcPeeringConnection extends Construct {
|
|
|
60
60
|
])
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
const hasPeerRoleArn = props.peerRoleArn !== undefined;
|
|
64
|
+
const hasPeerRegion = props.peerRegion !== undefined;
|
|
65
|
+
const hasPeerRouteTableIds = props.peerRouteTableIds !== undefined &&
|
|
66
|
+
props.peerRouteTableIds.length > 0;
|
|
67
|
+
const presentCount = Number(hasPeerRoleArn) +
|
|
68
|
+
Number(hasPeerRegion) +
|
|
69
|
+
Number(hasPeerRouteTableIds);
|
|
70
|
+
if (presentCount > 0 && presentCount < 3) {
|
|
71
|
+
const missing = [];
|
|
72
|
+
if (!hasPeerRoleArn)
|
|
73
|
+
missing.push("peerRoleArn");
|
|
74
|
+
if (!hasPeerRegion)
|
|
75
|
+
missing.push("peerRegion");
|
|
76
|
+
if (!hasPeerRouteTableIds)
|
|
77
|
+
missing.push("peerRouteTableIds");
|
|
78
|
+
throw new Error(`VpcPeeringConnection: cross-account return routes require all of ` +
|
|
79
|
+
`peerRoleArn, peerRegion, and peerRouteTableIds (non-empty). Missing: ${missing.join(", ")}.`);
|
|
80
|
+
}
|
|
81
|
+
if (props.peerRoleArn !== undefined &&
|
|
82
|
+
props.peerRegion !== undefined &&
|
|
83
|
+
props.peerRouteTableIds !== undefined &&
|
|
66
84
|
props.peerRouteTableIds.length > 0) {
|
|
67
85
|
new CrossAccountReturnRoutes(this, "ReturnRoutes", {
|
|
68
86
|
peerRoleArn: props.peerRoleArn,
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
+
import { type IFunction } from "aws-cdk-lib/aws-lambda";
|
|
2
3
|
import { LambdaFunction } from "../compute/lambda.js";
|
|
3
|
-
export interface CostAllocationTagActivatorProps {
|
|
4
|
-
/** EventBridge schedule expression. Default: "rate(24 hours)" */
|
|
5
|
-
scheduleExpression?: string;
|
|
6
|
-
}
|
|
7
4
|
/**
|
|
8
5
|
* Deploys a Lambda that auto-discovers and activates cost allocation tags.
|
|
9
6
|
*
|
|
10
7
|
* Runs daily in the management account. Any non-AWS tag applied to resources
|
|
11
8
|
* (via app.addTags() or CDK aspects) is automatically activated in Cost
|
|
12
9
|
* Explorer within 24 hours — no manual intervention required.
|
|
10
|
+
*
|
|
11
|
+
* The schedule is NOT wired by this construct — callers wire the cadence via
|
|
12
|
+
* `app.addSchedule(...)` so the EventBridge rule lives in the App's messaging
|
|
13
|
+
* stack alongside every other Fjall schedule (D9). The activator implements
|
|
14
|
+
* the structural `LambdaComputeShape` (duck-typed by `eventTargets.ts`), so it
|
|
15
|
+
* can be passed directly as `target` to `app.addSchedule(...)` without a
|
|
16
|
+
* `LambdaCompute` wrapper.
|
|
13
17
|
*/
|
|
14
18
|
export declare class CostAllocationTagActivator extends Construct {
|
|
19
|
+
/** Marks this construct as a structural Lambda target for `eventTargets.ts`. */
|
|
20
|
+
readonly computeType: "lambda";
|
|
15
21
|
readonly lambda: LambdaFunction;
|
|
16
|
-
constructor(scope: Construct, id: string
|
|
22
|
+
constructor(scope: Construct, id: string);
|
|
23
|
+
/**
|
|
24
|
+
* Structural `LambdaComputeShape` accessor — returns the activator's Lambda
|
|
25
|
+
* so `eventTargets.ts#resolveTarget` can wire it as an EventBridge target.
|
|
26
|
+
*/
|
|
27
|
+
getFunction(): IFunction;
|
|
17
28
|
}
|
|
@@ -8,12 +8,20 @@ import { LambdaFunction } from "../compute/lambda.js";
|
|
|
8
8
|
* Runs daily in the management account. Any non-AWS tag applied to resources
|
|
9
9
|
* (via app.addTags() or CDK aspects) is automatically activated in Cost
|
|
10
10
|
* Explorer within 24 hours — no manual intervention required.
|
|
11
|
+
*
|
|
12
|
+
* The schedule is NOT wired by this construct — callers wire the cadence via
|
|
13
|
+
* `app.addSchedule(...)` so the EventBridge rule lives in the App's messaging
|
|
14
|
+
* stack alongside every other Fjall schedule (D9). The activator implements
|
|
15
|
+
* the structural `LambdaComputeShape` (duck-typed by `eventTargets.ts`), so it
|
|
16
|
+
* can be passed directly as `target` to `app.addSchedule(...)` without a
|
|
17
|
+
* `LambdaCompute` wrapper.
|
|
11
18
|
*/
|
|
12
19
|
export class CostAllocationTagActivator extends Construct {
|
|
20
|
+
/** Marks this construct as a structural Lambda target for `eventTargets.ts`. */
|
|
21
|
+
computeType = "lambda";
|
|
13
22
|
lambda;
|
|
14
|
-
constructor(scope, id
|
|
23
|
+
constructor(scope, id) {
|
|
15
24
|
super(scope, id);
|
|
16
|
-
const schedule = props?.scheduleExpression ?? "rate(24 hours)";
|
|
17
25
|
this.lambda = new LambdaFunction(this, "TagActivatorFunction", {
|
|
18
26
|
runtime: Runtime.NODEJS_22_X,
|
|
19
27
|
handler: "index.handler",
|
|
@@ -21,7 +29,6 @@ export class CostAllocationTagActivator extends Construct {
|
|
|
21
29
|
lambdaDescription: "Auto-discovers and activates cost allocation tags in Cost Explorer",
|
|
22
30
|
memorySize: 128,
|
|
23
31
|
timeout: 60,
|
|
24
|
-
scheduleExpression: schedule,
|
|
25
32
|
inlinePolicy: [
|
|
26
33
|
new PolicyStatement({
|
|
27
34
|
effect: Effect.ALLOW,
|
|
@@ -34,6 +41,13 @@ export class CostAllocationTagActivator extends Construct {
|
|
|
34
41
|
]
|
|
35
42
|
});
|
|
36
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Structural `LambdaComputeShape` accessor — returns the activator's Lambda
|
|
46
|
+
* so `eventTargets.ts#resolveTarget` can wire it as an EventBridge target.
|
|
47
|
+
*/
|
|
48
|
+
getFunction() {
|
|
49
|
+
return this.lambda;
|
|
50
|
+
}
|
|
37
51
|
}
|
|
38
52
|
const HANDLER_CODE = `
|
|
39
53
|
const { CostExplorerClient, ListCostAllocationTagsCommand, UpdateCostAllocationTagsStatusCommand } = require("@aws-sdk/client-cost-explorer");
|
|
@@ -2,4 +2,4 @@ export { Organisation as OrganisationResource, type OrganisationProps as Organis
|
|
|
2
2
|
export { type OrganisationalUnitProps } from "./organisationalUnit.js";
|
|
3
3
|
export { OrganisationAccount, type OrganisationAccountProps } from "./organisationAccount.js";
|
|
4
4
|
export { OrganisationPolicy, type OrganisationPolicyProps, type OrganisationPolicyType } from "./organisationPolicy.js";
|
|
5
|
-
export { CostAllocationTagActivator
|
|
5
|
+
export { CostAllocationTagActivator } from "./costAllocationTagActivator.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
+
import { type KeyValue } from "../../../types.js";
|
|
2
3
|
export type OrganisationPolicyType = "SERVICE_CONTROL_POLICY" | "TAG_POLICY" | "BACKUP_POLICY" | "AISERVICES_OPT_OUT_POLICY";
|
|
3
4
|
export interface OrganisationPolicyProps {
|
|
4
5
|
name: string;
|
|
@@ -6,6 +7,7 @@ export interface OrganisationPolicyProps {
|
|
|
6
7
|
content: string | Record<string, unknown>;
|
|
7
8
|
description?: string;
|
|
8
9
|
targetIds?: string[];
|
|
10
|
+
tags?: KeyValue[];
|
|
9
11
|
}
|
|
10
12
|
export declare class OrganisationPolicy extends Construct {
|
|
11
13
|
readonly policyId: string;
|
|
@@ -10,7 +10,7 @@ export class OrganisationPolicy extends Construct {
|
|
|
10
10
|
content = JSON.parse(props.content);
|
|
11
11
|
}
|
|
12
12
|
catch {
|
|
13
|
-
throw new Error(`Invalid JSON in organisation policy "${props.name}"
|
|
13
|
+
throw new Error(`Invalid JSON in organisation policy "${props.name}"`);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
@@ -21,7 +21,8 @@ export class OrganisationPolicy extends Construct {
|
|
|
21
21
|
type: props.policyType,
|
|
22
22
|
content,
|
|
23
23
|
description: props.description,
|
|
24
|
-
targetIds: props.targetIds
|
|
24
|
+
targetIds: props.targetIds,
|
|
25
|
+
tags: props.tags?.map((t) => ({ key: t.key, value: t.value }))
|
|
25
26
|
});
|
|
26
27
|
this.policyId = policy.attrId;
|
|
27
28
|
}
|
|
@@ -8,6 +8,13 @@ interface SecretProps {
|
|
|
8
8
|
secretObjectValue?: {
|
|
9
9
|
[key: string]: SecretValue;
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Plain-text secret value. WARNING: embedded in the CloudFormation template
|
|
13
|
+
* via `SecretValue.unsafePlainText` — anyone with read access to the synth
|
|
14
|
+
* output, the deploy artefact, or the CFN stack template can recover it.
|
|
15
|
+
* Prefer `generateSecretString` (server-generated, never leaves AWS) or
|
|
16
|
+
* `secretObjectValue` with `SecretValue.ssmSecure(...)` for inputs.
|
|
17
|
+
*/
|
|
11
18
|
secretStringValue?: string;
|
|
12
19
|
description?: string;
|
|
13
20
|
aliasName?: string;
|
|
@@ -17,15 +17,16 @@ export class Secret extends Construct {
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
// Create KMS key for new secrets only
|
|
20
|
-
|
|
20
|
+
const customerManagedKey = new CustomerManagedKey(this, `${id}CustomerManagedKey`, {
|
|
21
21
|
aliasName: `cmk/${id}`
|
|
22
22
|
});
|
|
23
|
+
this.secretsCustomerManagedKey = customerManagedKey;
|
|
23
24
|
/**
|
|
24
25
|
* If a secretStringValue is provided, use it to create the secret.
|
|
25
26
|
*/
|
|
26
27
|
const secretStringValue = props.secretStringValue
|
|
27
28
|
? {
|
|
28
|
-
secretStringValue: SecretValue.unsafePlainText(props.secretStringValue
|
|
29
|
+
secretStringValue: SecretValue.unsafePlainText(props.secretStringValue)
|
|
29
30
|
}
|
|
30
31
|
: {};
|
|
31
32
|
/**
|
|
@@ -47,7 +48,7 @@ export class Secret extends Construct {
|
|
|
47
48
|
const secretOptions = {
|
|
48
49
|
secretName: props.secretName,
|
|
49
50
|
secretObjectValue: props.secretObjectValue,
|
|
50
|
-
encryptionKey:
|
|
51
|
+
encryptionKey: customerManagedKey.key,
|
|
51
52
|
description: props.description,
|
|
52
53
|
...secretStringValue,
|
|
53
54
|
...generateSecretString,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BucketDeployment as CdkBucketDeployment, type BucketDeploymentProps } from "aws-cdk-lib/aws-s3-deployment";
|
|
2
|
+
import { type Construct } from "constructs";
|
|
3
|
+
/**
|
|
4
|
+
* Routing-point wrapper for `aws-cdk-lib/aws-s3-deployment.BucketDeployment`.
|
|
5
|
+
*
|
|
6
|
+
* Currently a thin pass-through — no defaults are applied today. The wrapper
|
|
7
|
+
* exists so that future SOC2 / compliance defaults (tags, retention, encryption
|
|
8
|
+
* on the underlying Lambda + Custom Resource) reach every consumer in one edit.
|
|
9
|
+
* Per `.claude/rules/generator-standards.md § Wrapper Routing Discipline` and
|
|
10
|
+
* `patterns/infrastructure-wrapper-routing-pattern.md § A3` ("a wrapper that
|
|
11
|
+
* is a thin pass-through today is still the routing point"), `lib/{config,
|
|
12
|
+
* patterns}/` MUST instantiate this class rather than the raw CDK construct.
|
|
13
|
+
*/
|
|
14
|
+
export declare class BucketDeployment extends CdkBucketDeployment {
|
|
15
|
+
constructor(scope: Construct, id: string, props: BucketDeploymentProps);
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BucketDeployment as CdkBucketDeployment } from "aws-cdk-lib/aws-s3-deployment";
|
|
2
|
+
/**
|
|
3
|
+
* Routing-point wrapper for `aws-cdk-lib/aws-s3-deployment.BucketDeployment`.
|
|
4
|
+
*
|
|
5
|
+
* Currently a thin pass-through — no defaults are applied today. The wrapper
|
|
6
|
+
* exists so that future SOC2 / compliance defaults (tags, retention, encryption
|
|
7
|
+
* on the underlying Lambda + Custom Resource) reach every consumer in one edit.
|
|
8
|
+
* Per `.claude/rules/generator-standards.md § Wrapper Routing Discipline` and
|
|
9
|
+
* `patterns/infrastructure-wrapper-routing-pattern.md § A3` ("a wrapper that
|
|
10
|
+
* is a thin pass-through today is still the routing point"), `lib/{config,
|
|
11
|
+
* patterns}/` MUST instantiate this class rather than the raw CDK construct.
|
|
12
|
+
*/
|
|
13
|
+
export class BucketDeployment extends CdkBucketDeployment {
|
|
14
|
+
constructor(scope, id, props) {
|
|
15
|
+
super(scope, id, props);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -24,14 +24,14 @@ export class Ecr extends Repository {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
static getRepositoryProps(props) {
|
|
27
|
-
//
|
|
28
|
-
//
|
|
27
|
+
// Gotcha: DESTROY + emptyOnDelete:true silently wipes every pushed image
|
|
28
|
+
// on stack teardown — next deploy pulls "not found" for any referenced tag.
|
|
29
29
|
return {
|
|
30
30
|
...(props?.repositoryName && { repositoryName: props.repositoryName }),
|
|
31
31
|
imageScanOnPush: true,
|
|
32
|
-
imageTagMutability: TagMutability.
|
|
33
|
-
emptyOnDelete:
|
|
34
|
-
removalPolicy: RemovalPolicy.
|
|
32
|
+
imageTagMutability: TagMutability.IMMUTABLE,
|
|
33
|
+
emptyOnDelete: false,
|
|
34
|
+
removalPolicy: RemovalPolicy.RETAIN
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
static build(id, props) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CfnOutput, Duration, RemovalPolicy } from "aws-cdk-lib";
|
|
2
2
|
import { BlockPublicAccess, Bucket } from "aws-cdk-lib/aws-s3";
|
|
3
|
+
import { RegionInfo } from "aws-cdk-lib/region-info";
|
|
3
4
|
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
4
5
|
function shouldAutoVersion(tier) {
|
|
5
6
|
return tier === "resilient" || tier === "enterprise";
|
|
@@ -36,18 +37,24 @@ export class S3Bucket extends Bucket {
|
|
|
36
37
|
});
|
|
37
38
|
this.backupVaultTier = backupVaultTier;
|
|
38
39
|
if (websiteHosting) {
|
|
39
|
-
const safeBucket = toPascalCase((props.bucketName ?? id).replace(/[^A-Za-z0-9]/g, ""));
|
|
40
|
+
const safeBucket = toPascalCase((props.bucketName ?? id).replace(/[^A-Za-z0-9-]/g, ""));
|
|
40
41
|
new CfnOutput(this, `${safeBucket}WebsiteEndpoint`, {
|
|
41
42
|
key: `${safeBucket}WebsiteEndpoint`,
|
|
42
43
|
exportName: `${safeBucket}WebsiteEndpoint`,
|
|
43
44
|
value: this.bucketWebsiteDomainName,
|
|
44
45
|
description: `S3 website endpoint for ${id} (consumed by Domain alias targets)`
|
|
45
46
|
});
|
|
47
|
+
const region = this.stack.region;
|
|
48
|
+
const websiteHostedZoneId = RegionInfo.get(region).s3StaticWebsiteHostedZoneId;
|
|
49
|
+
if (websiteHostedZoneId === undefined) {
|
|
50
|
+
throw new Error(`S3 website hosted zone id is not known for region "${region}". ` +
|
|
51
|
+
`Update aws-cdk-lib/region-info or provide the bucket's hosted zone id explicitly.`);
|
|
52
|
+
}
|
|
46
53
|
new CfnOutput(this, `${safeBucket}WebsiteHostedZoneId`, {
|
|
47
54
|
key: `${safeBucket}WebsiteHostedZoneId`,
|
|
48
55
|
exportName: `${safeBucket}WebsiteHostedZoneId`,
|
|
49
|
-
value:
|
|
50
|
-
description: `
|
|
56
|
+
value: websiteHostedZoneId,
|
|
57
|
+
description: `Route 53 hosted zone id for the S3 website endpoint of ${id}`
|
|
51
58
|
});
|
|
52
59
|
}
|
|
53
60
|
}
|
|
@@ -3,6 +3,7 @@ import { Provider } from "aws-cdk-lib/custom-resources";
|
|
|
3
3
|
import { Code } from "aws-cdk-lib/aws-lambda";
|
|
4
4
|
import { Construct } from "constructs";
|
|
5
5
|
import { SingletonFunction, LambdaFunction } from "../compute/lambda.js";
|
|
6
|
+
import { DEFAULT_CUSTOM_RESOURCE_TIMEOUT_SECONDS } from "../compute/ecsConstants.js";
|
|
6
7
|
export class CustomResource extends Construct {
|
|
7
8
|
response;
|
|
8
9
|
resource;
|
|
@@ -15,12 +16,20 @@ export class CustomResource extends Construct {
|
|
|
15
16
|
if (props.codePath && props.inlineCode) {
|
|
16
17
|
throw new Error("CustomResource requires exactly one of codePath or inlineCode, not both");
|
|
17
18
|
}
|
|
18
|
-
const isInlineCode =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const isInlineCode = props.inlineCode !== undefined;
|
|
20
|
+
let code;
|
|
21
|
+
if (props.inlineCode !== undefined) {
|
|
22
|
+
code = Code.fromInline(props.inlineCode);
|
|
23
|
+
}
|
|
24
|
+
else if (props.codePath !== undefined) {
|
|
25
|
+
code = Code.fromAsset(props.codePath, props.assetOptions);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Unreachable — earlier validation rejects this case
|
|
29
|
+
throw new Error("CustomResource requires codePath or inlineCode");
|
|
30
|
+
}
|
|
22
31
|
const handler = props.handler ?? (isInlineCode ? "index.handler" : `${id}.handler`);
|
|
23
|
-
const timeout = props.timeout?.toSeconds() ??
|
|
32
|
+
const timeout = props.timeout?.toSeconds() ?? DEFAULT_CUSTOM_RESOURCE_TIMEOUT_SECONDS;
|
|
24
33
|
// Use LambdaFunction for inline code (unique per use), SingletonFunction for assets (shared)
|
|
25
34
|
const lambdaFunction = isInlineCode
|
|
26
35
|
? new LambdaFunction(this, `${id}Lambda`, {
|
|
@@ -28,16 +37,16 @@ export class CustomResource extends Construct {
|
|
|
28
37
|
handler,
|
|
29
38
|
runtime: props.runtime,
|
|
30
39
|
timeout,
|
|
31
|
-
lambdaDescription: props.lambdaDescription
|
|
32
|
-
roleDescription: props.roleDescription
|
|
40
|
+
lambdaDescription: props.lambdaDescription ?? `${id} lambda`,
|
|
41
|
+
roleDescription: props.roleDescription ?? `${id} custom resource lambda`,
|
|
33
42
|
inlinePolicy: props.inlinePolicy
|
|
34
43
|
})
|
|
35
44
|
: new SingletonFunction(this, `${id}Lambda`, {
|
|
36
45
|
code,
|
|
37
46
|
handler,
|
|
38
47
|
runtime: props.runtime,
|
|
39
|
-
lambdaDescription: props.lambdaDescription
|
|
40
|
-
roleDescription: props.roleDescription
|
|
48
|
+
lambdaDescription: props.lambdaDescription ?? `${id} lambda`,
|
|
49
|
+
roleDescription: props.roleDescription ?? `${id} custom resource lambda`,
|
|
41
50
|
inlinePolicy: props.inlinePolicy
|
|
42
51
|
});
|
|
43
52
|
const provider = new Provider(this, `${id}Provider`, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { App, Stack } from "aws-cdk-lib";
|
|
2
|
+
import { Template } from "aws-cdk-lib/assertions";
|
|
3
|
+
import { Vpc } from "aws-cdk-lib/aws-ec2";
|
|
4
|
+
import { Repository } from "aws-cdk-lib/aws-ecr";
|
|
5
|
+
import { mkdtempSync, mkdirSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { EcsCompute } from "./patterns/aws/computeEcs.js";
|
|
9
|
+
import { RelationalDatabase } from "./patterns/aws/database.js";
|
|
10
|
+
const root = mkdtempSync(join(tmpdir(), "ds-"));
|
|
11
|
+
mkdirSync(join(root, "20260512000000_init"));
|
|
12
|
+
const app = new App();
|
|
13
|
+
const stack = new Stack(app, "S", { env: { account: "123456789012", region: "us-east-1" } });
|
|
14
|
+
const vpc = new Vpc(stack, "Vpc");
|
|
15
|
+
const db = new RelationalDatabase(stack, "Db", {
|
|
16
|
+
type: "Instance", vpc, databaseName: "appdata",
|
|
17
|
+
migrations: { tool: "prisma", dir: root }
|
|
18
|
+
});
|
|
19
|
+
new EcsCompute(stack, "Cluster", {
|
|
20
|
+
type: "ecs",
|
|
21
|
+
ecrRepository: new Repository(stack, "Ecr"),
|
|
22
|
+
services: [{
|
|
23
|
+
name: "web", capacityProvider: "FARGATE",
|
|
24
|
+
containers: [{ name: "app", image: "nginx:latest", port: 3000 }],
|
|
25
|
+
connections: [db],
|
|
26
|
+
migrations: {
|
|
27
|
+
mode: "lifecycle-hook", command: ["node", "migrate.mjs"], entryPoint: ["/usr/bin/tini", "--"],
|
|
28
|
+
separateTaskDef: { cpu: 512, memoryLimitMiB: 1024 }
|
|
29
|
+
}
|
|
30
|
+
}]
|
|
31
|
+
});
|
|
32
|
+
const t = Template.fromStack(stack);
|
|
33
|
+
const ing = t.findResources("AWS::EC2::SecurityGroupIngress");
|
|
34
|
+
for (const [name, res] of Object.entries(ing)) {
|
|
35
|
+
console.log("INGRESS:", name);
|
|
36
|
+
console.log(" props:", JSON.stringify(res.Properties));
|
|
37
|
+
}
|
|
38
|
+
const eg = t.findResources("AWS::EC2::SecurityGroupEgress");
|
|
39
|
+
for (const [name, res] of Object.entries(eg)) {
|
|
40
|
+
console.log("EGRESS:", name);
|
|
41
|
+
console.log(" props:", JSON.stringify(res.Properties));
|
|
42
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Node } from "constructs";
|
|
2
2
|
export declare const CDK_CONTEXT_KEYS: {
|
|
3
3
|
readonly ORG_ID: "orgId";
|
|
4
|
+
readonly ROOT_ID: "rootId";
|
|
5
|
+
readonly MANAGEMENT_ACCOUNT_ID: "managementAccountId";
|
|
4
6
|
};
|
|
5
7
|
export declare const DEFAULT_ORG_ID: "default";
|
|
6
8
|
export declare function resolveOrgId(node: Node, fallback: string): string;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export const CDK_CONTEXT_KEYS = {
|
|
2
|
-
ORG_ID: "orgId"
|
|
2
|
+
ORG_ID: "orgId",
|
|
3
|
+
ROOT_ID: "rootId",
|
|
4
|
+
MANAGEMENT_ACCOUNT_ID: "managementAccountId"
|
|
3
5
|
};
|
|
4
6
|
export const DEFAULT_ORG_ID = "default";
|
|
5
7
|
export function resolveOrgId(node, fallback) {
|
|
6
8
|
const raw = node.tryGetContext(CDK_CONTEXT_KEYS.ORG_ID);
|
|
7
|
-
return typeof raw === "string" ? raw : fallback;
|
|
9
|
+
return typeof raw === "string" && raw !== "" ? raw : fallback;
|
|
8
10
|
}
|
|
9
11
|
export function buildSsmPrefix(orgId, appName) {
|
|
10
12
|
return `/fjall/${orgId}/${appName}`;
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* this.lambdaFunction // IConnectable (security group)
|
|
22
22
|
* );
|
|
23
23
|
*/
|
|
24
|
+
import { Port } from "aws-cdk-lib/aws-ec2";
|
|
24
25
|
import { CONNECTION_TYPE, isConnectionConfig, isConnector, isConnectable, isConnectionAccess, isMessagingAccess } from "./connector.js";
|
|
25
26
|
/** Default access levels for each connector type. */
|
|
26
27
|
const DEFAULT_ACCESS = {
|
|
@@ -140,6 +141,11 @@ export function processConnections(connections, grantee, connectable) {
|
|
|
140
141
|
case "relational": {
|
|
141
142
|
requireConnectable(connectable, `${resource.connectorType} connector`);
|
|
142
143
|
connectable.connections.allowToDefaultPort(resource);
|
|
144
|
+
if (resource.additionalTcpPorts !== undefined) {
|
|
145
|
+
for (const port of resource.additionalTcpPorts) {
|
|
146
|
+
connectable.connections.allowTo(resource, Port.tcp(port));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
143
149
|
return buildSecurityGroupResult(resource);
|
|
144
150
|
}
|
|
145
151
|
case "remote": {
|
|
@@ -115,6 +115,18 @@ export interface ISecurityGroupConnector extends IConnector {
|
|
|
115
115
|
readonly connectorType: "securityGroup" | "relational";
|
|
116
116
|
/** The security group connections for this resource. */
|
|
117
117
|
readonly connections: IConnectable["connections"];
|
|
118
|
+
/**
|
|
119
|
+
* Additional TCP ports to open beyond the default port carried by
|
|
120
|
+
* `connections`. Used by dual-port resources such as ClickHouse, where the
|
|
121
|
+
* primary port (HTTP, 8123) flows through `connections.allowDefaultPortFrom`
|
|
122
|
+
* and the native protocol port (9000) is appended here. Optional; existing
|
|
123
|
+
* single-port consumers (Aurora, Instance, GlobalAurora) leave this
|
|
124
|
+
* undefined and behave unchanged.
|
|
125
|
+
*
|
|
126
|
+
* Surfaced as `number[]` (not `aws-cdk-lib/aws-ec2.Port[]`) per the
|
|
127
|
+
* 2026-05-05 ClickHouse design D18(k); `Port.tcp(n)` is plumbing.
|
|
128
|
+
*/
|
|
129
|
+
readonly additionalTcpPorts?: number[];
|
|
118
130
|
}
|
|
119
131
|
/**
|
|
120
132
|
* Remote connector interface.
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import type { IConstruct } from "constructs";
|
|
1
2
|
export declare const COST_ALLOCATION_TAGS: {
|
|
2
3
|
readonly ENVIRONMENT: "fjall:costAllocation:environment";
|
|
3
4
|
readonly SERVICE: "fjall:costAllocation:service";
|
|
4
5
|
readonly DOMAIN: "fjall:costAllocation:domain";
|
|
6
|
+
readonly OWNER: "fjall:costAllocation:owner";
|
|
5
7
|
};
|
|
6
8
|
export declare const DEFAULT_COST_ALLOCATION_ENVIRONMENT: "management";
|
|
9
|
+
export interface CostAllocationTagsArgs {
|
|
10
|
+
readonly service: string;
|
|
11
|
+
readonly domain: string;
|
|
12
|
+
readonly environment?: string;
|
|
13
|
+
readonly owner?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function applyCostAllocationTags(scope: IConstruct, args: CostAllocationTagsArgs): void;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import { Tags } from "aws-cdk-lib";
|
|
1
2
|
export const COST_ALLOCATION_TAGS = {
|
|
2
3
|
ENVIRONMENT: "fjall:costAllocation:environment",
|
|
3
4
|
SERVICE: "fjall:costAllocation:service",
|
|
4
|
-
DOMAIN: "fjall:costAllocation:domain"
|
|
5
|
+
DOMAIN: "fjall:costAllocation:domain",
|
|
6
|
+
OWNER: "fjall:costAllocation:owner"
|
|
5
7
|
};
|
|
6
8
|
export const DEFAULT_COST_ALLOCATION_ENVIRONMENT = "management";
|
|
9
|
+
export function applyCostAllocationTags(scope, args) {
|
|
10
|
+
Tags.of(scope).add(COST_ALLOCATION_TAGS.ENVIRONMENT, args.environment ?? DEFAULT_COST_ALLOCATION_ENVIRONMENT);
|
|
11
|
+
Tags.of(scope).add(COST_ALLOCATION_TAGS.SERVICE, args.service);
|
|
12
|
+
Tags.of(scope).add(COST_ALLOCATION_TAGS.DOMAIN, args.domain);
|
|
13
|
+
if (args.owner !== undefined) {
|
|
14
|
+
Tags.of(scope).add(COST_ALLOCATION_TAGS.OWNER, args.owner);
|
|
15
|
+
}
|
|
16
|
+
}
|