@fjall/components-infrastructure 0.95.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 +90 -107
- package/dist/lib/app.js +149 -139
- 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 +7 -8
- 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 +95 -396
- package/dist/lib/patterns/aws/computeEcs.js +880 -46
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +889 -0
- package/dist/lib/patterns/aws/computeEcsTypes.js +12 -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 +8 -7
- package/dist/lib/patterns/aws/index.d.ts +3 -0
- package/dist/lib/patterns/aws/index.js +3 -0
- package/dist/lib/patterns/aws/interfaces/compute.d.ts +13 -1
- package/dist/lib/patterns/aws/interfaces/connector.d.ts +1 -1
- package/dist/lib/patterns/aws/interfaces/connector.js +1 -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 +4 -2
- package/dist/lib/patterns/aws/interfaces/index.js +4 -2
- 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/interfaces/vpcPeer.d.ts +7 -0
- package/dist/lib/patterns/aws/interfaces/vpcPeer.js +1 -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 +24 -5
- 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.d.ts +34 -0
- package/dist/lib/patterns/aws/vpcPeer.js +38 -0
- package/dist/lib/patterns/aws/vpcPeerAccepter.d.ts +29 -0
- package/dist/lib/patterns/aws/vpcPeerAccepter.js +196 -0
- package/dist/lib/resources/aws/analytics/clickhouse.js +25 -7
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +49 -0
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +140 -0
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +4 -4
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +6 -4
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +12 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +56 -5
- package/dist/lib/resources/aws/analytics/index.d.ts +2 -0
- package/dist/lib/resources/aws/analytics/index.js +1 -0
- 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/ecsRemoteConnections.d.ts +38 -0
- package/dist/lib/resources/aws/compute/ecsRemoteConnections.js +80 -0
- 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 +110 -6
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +180 -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 +12 -5
- 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 -3
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.d.ts +40 -0
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +158 -0
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -4
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
- package/dist/lib/resources/aws/networking/domainCertificate.js +6 -3
- package/dist/lib/resources/aws/networking/hostedZone.js +6 -4
- package/dist/lib/resources/aws/networking/index.d.ts +3 -0
- package/dist/lib/resources/aws/networking/index.js +3 -0
- 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 +10 -3
- package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.d.ts +18 -0
- package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.js +61 -0
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.d.ts +49 -0
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +106 -0
- 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/bastionFactory.d.ts +10 -0
- package/dist/lib/utils/bastionFactory.js +29 -0
- package/dist/lib/utils/capitaliseString.d.ts +1 -1
- package/dist/lib/utils/capitaliseString.js +1 -1
- package/dist/lib/utils/cdkContext.d.ts +10 -0
- package/dist/lib/utils/cdkContext.js +13 -0
- package/dist/lib/utils/connections.d.ts +7 -1
- package/dist/lib/utils/connections.js +21 -0
- package/dist/lib/utils/connector.d.ts +30 -2
- package/dist/lib/utils/connector.js +6 -1
- package/dist/lib/utils/costAllocationTags.d.ts +15 -0
- package/dist/lib/utils/costAllocationTags.js +16 -0
- 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 +4 -0
- package/dist/lib/utils/index.js +4 -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/dist/lib/utils/vpcPeerInterface.d.ts +22 -0
- package/dist/lib/utils/vpcPeerInterface.js +1 -0
- package/package.json +22 -18
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { Duration } from "aws-cdk-lib";
|
|
3
|
+
import { type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
4
|
+
import { type IPrivateDnsNamespace, type IService } from "aws-cdk-lib/aws-servicediscovery";
|
|
5
|
+
/**
|
|
6
|
+
* Plumbing-only base resource wrapping `aws-cdk-lib/aws-servicediscovery`'s
|
|
7
|
+
* `PrivateDnsNamespace`. Per D7 + D29 of the ClickHouse Database Factory
|
|
8
|
+
* promotion design, the only consumer entry point is `App.getNamespace()` —
|
|
9
|
+
* this class is NOT re-exported from `lib/index.ts`.
|
|
10
|
+
*
|
|
11
|
+
* No `static fromXxx(...)` factory is exposed: cross-stack consumption is
|
|
12
|
+
* single-stack-only for v1 per D29. If/when cross-stack arises, a `fromXxx`
|
|
13
|
+
* factory lands then, not now.
|
|
14
|
+
*/
|
|
15
|
+
export interface ServiceDiscoveryNamespaceProps {
|
|
16
|
+
vpc: IVpc;
|
|
17
|
+
name: string;
|
|
18
|
+
/** Override the default description (`"ServiceDiscovery <name> — Fjall private DNS namespace"`). */
|
|
19
|
+
description?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Removal policy. Default resolves via the `env()` helper (production →
|
|
22
|
+
* RETAIN; non-prod → DESTROY) — matches the convention codified in D17 of
|
|
23
|
+
* the EventBridge promotion design. NODE_ENV is intentionally NOT consulted
|
|
24
|
+
* because it is unset during CDK synth in Fjall's deployment paths.
|
|
25
|
+
*/
|
|
26
|
+
removalPolicy?: "DESTROY" | "RETAIN";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Properties for registering a Cloud Map service inside the namespace via
|
|
30
|
+
* `registerService(...)`. Single source of truth for the second-tier wrapper
|
|
31
|
+
* around `AWS::ServiceDiscovery::Service`. Per D7(d), this method is
|
|
32
|
+
* internal-only — never consumed directly from user infrastructure code.
|
|
33
|
+
*/
|
|
34
|
+
export interface ServiceRegistrationProps {
|
|
35
|
+
/** Service name within the namespace (forms the leftmost label of the FQDN). */
|
|
36
|
+
name: string;
|
|
37
|
+
/**
|
|
38
|
+
* Description override. Default: `"Fjall internal service: <name>"`.
|
|
39
|
+
* Operators see this in the Cloud Map console; explicit overrides are
|
|
40
|
+
* preferred when the service name alone is ambiguous (e.g. `"clickhouse"`
|
|
41
|
+
* is fine; `"web"` benefits from a description naming the role).
|
|
42
|
+
*/
|
|
43
|
+
description?: string;
|
|
44
|
+
/**
|
|
45
|
+
* DNS TTL applied to the A records returned for this service. Default:
|
|
46
|
+
* 60 seconds — matches CDK's implicit ECS default. Raise for stable
|
|
47
|
+
* services (cuts query volume); lower for rapidly-changing instance sets.
|
|
48
|
+
*/
|
|
49
|
+
dnsTtl?: Duration;
|
|
50
|
+
/**
|
|
51
|
+
* DNS record type. Default `"A"` — appropriate for `awsvpc` ECS services
|
|
52
|
+
* where each task has its own ENI IP. Set to `"SRV"` when the consumer is
|
|
53
|
+
* an ECS service running under `host` or `bridge` network mode: SRV records
|
|
54
|
+
* carry both the host IP and the published port, which `A` records cannot.
|
|
55
|
+
* CDK's `Ec2Service.associateCloudMapService(...)` requires SRV (and a
|
|
56
|
+
* `containerName` + `containerPort`) under those modes.
|
|
57
|
+
*/
|
|
58
|
+
dnsRecordType?: "A" | "SRV";
|
|
59
|
+
}
|
|
60
|
+
export declare class ServiceDiscoveryNamespace extends Construct {
|
|
61
|
+
#private;
|
|
62
|
+
readonly id: string;
|
|
63
|
+
constructor(scope: Construct, id: string, props: ServiceDiscoveryNamespaceProps);
|
|
64
|
+
/**
|
|
65
|
+
* Get the underlying CDK private DNS namespace as the `IPrivateDnsNamespace`
|
|
66
|
+
* interface. Per D18(a), the public surface is the interface, never the
|
|
67
|
+
* concrete `PrivateDnsNamespace` class.
|
|
68
|
+
*/
|
|
69
|
+
getNamespace(): IPrivateDnsNamespace;
|
|
70
|
+
getNamespaceArn(): string;
|
|
71
|
+
getNamespaceName(): string;
|
|
72
|
+
/**
|
|
73
|
+
* Register a Cloud Map service inside this namespace. Creates an
|
|
74
|
+
* `AWS::ServiceDiscovery::Service` resource via the underlying CDK
|
|
75
|
+
* `PrivateDnsNamespace.createService(...)` with Fjall description discipline
|
|
76
|
+
* applied. Internal-only per D7(d) — Fjall resources call this from inside
|
|
77
|
+
* their construct bodies; user code never invokes it directly.
|
|
78
|
+
*
|
|
79
|
+
* Throws on duplicate registration: a single namespace cannot host two
|
|
80
|
+
* services with the same DNS name. Caught at synth time, not deploy time.
|
|
81
|
+
*/
|
|
82
|
+
registerService(props: ServiceRegistrationProps): IService;
|
|
83
|
+
/**
|
|
84
|
+
* True if a service with this name has been registered in the namespace.
|
|
85
|
+
* Cheap registry lookup; does NOT consult AWS — only counts services
|
|
86
|
+
* registered via `registerService(...)` on this construct.
|
|
87
|
+
*/
|
|
88
|
+
hasService(name: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Build the FQDN for a previously-registered service:
|
|
91
|
+
* `<serviceName>.<namespaceName>` (e.g. `clickhouse.acme.local`). Throws if
|
|
92
|
+
* the service has not been registered — prevents typos that would silently
|
|
93
|
+
* resolve to NXDOMAIN at runtime.
|
|
94
|
+
*/
|
|
95
|
+
getEndpoint(serviceName: string): string;
|
|
96
|
+
}
|
|
@@ -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;
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { Duration, RemovalPolicy, Stack } from "aws-cdk-lib";
|
|
1
|
+
import { CfnOutput, Duration, RemovalPolicy, Stack } from "aws-cdk-lib";
|
|
2
2
|
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
|
-
super(scope, `
|
|
18
|
+
super(scope, `Vpc${id}`, {
|
|
16
19
|
...restProps,
|
|
17
20
|
vpcName,
|
|
18
21
|
natGateways,
|
|
@@ -23,6 +26,10 @@ export class Vpc extends ec2.Vpc {
|
|
|
23
26
|
});
|
|
24
27
|
this.hasNatGateways = natGateways !== 0;
|
|
25
28
|
this.addInterfaceEndpoints(id, props, this.hasNatGateways);
|
|
29
|
+
new CfnOutput(this, "VpcCidrBlock", {
|
|
30
|
+
value: this.vpcCidrBlock,
|
|
31
|
+
exportName: `${Stack.of(this).stackName}-vpc-cidr`
|
|
32
|
+
});
|
|
26
33
|
}
|
|
27
34
|
static gatewayEndpoints(props) {
|
|
28
35
|
if (props?.endpointsConfig === false) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { Role } from "aws-cdk-lib/aws-iam";
|
|
3
|
+
import { type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
4
|
+
export interface VpcPeeringAccepterRoleProps {
|
|
5
|
+
/** AWS account IDs allowed to initiate peering and manage return routes. */
|
|
6
|
+
readonly requesterAccountIds: string[];
|
|
7
|
+
/** The local VPC this role is scoped to. */
|
|
8
|
+
readonly localVpc: IVpc;
|
|
9
|
+
/** Cost-allocation override — defaults to `"management"`. */
|
|
10
|
+
readonly costAllocationEnvironment?: string;
|
|
11
|
+
/** Cost-allocation override — defaults to the local VPC's construct id. */
|
|
12
|
+
readonly costAllocationDomain?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class VpcPeeringAccepterRole extends Construct {
|
|
15
|
+
readonly role: Role;
|
|
16
|
+
readonly roleArn: string;
|
|
17
|
+
constructor(scope: Construct, id: string, props: VpcPeeringAccepterRoleProps);
|
|
18
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { ArnFormat, Stack, Tags } from "aws-cdk-lib";
|
|
3
|
+
import { AccountPrincipal, CompositePrincipal, PolicyDocument, PolicyStatement, Role } from "aws-cdk-lib/aws-iam";
|
|
4
|
+
import { COST_ALLOCATION_TAGS, DEFAULT_COST_ALLOCATION_ENVIRONMENT } from "../../../utils/costAllocationTags.js";
|
|
5
|
+
export class VpcPeeringAccepterRole extends Construct {
|
|
6
|
+
role;
|
|
7
|
+
roleArn;
|
|
8
|
+
constructor(scope, id, props) {
|
|
9
|
+
super(scope, id);
|
|
10
|
+
const vpcArnPattern = Stack.of(this).formatArn({
|
|
11
|
+
service: "ec2",
|
|
12
|
+
region: "*",
|
|
13
|
+
account: "*",
|
|
14
|
+
resource: "vpc",
|
|
15
|
+
resourceName: props.localVpc.vpcId,
|
|
16
|
+
arnFormat: ArnFormat.SLASH_RESOURCE_NAME
|
|
17
|
+
});
|
|
18
|
+
this.role = new Role(this, "Role", {
|
|
19
|
+
assumedBy: new CompositePrincipal(...props.requesterAccountIds.map((accountId) => new AccountPrincipal(accountId))),
|
|
20
|
+
inlinePolicies: {
|
|
21
|
+
allowPeering: new PolicyDocument({
|
|
22
|
+
statements: [
|
|
23
|
+
new PolicyStatement({
|
|
24
|
+
actions: [
|
|
25
|
+
"ec2:AcceptVpcPeeringConnection",
|
|
26
|
+
"ec2:ModifyVpcPeeringConnectionOptions"
|
|
27
|
+
],
|
|
28
|
+
resources: ["*"],
|
|
29
|
+
conditions: {
|
|
30
|
+
StringEquals: {
|
|
31
|
+
"ec2:AccepterVpc": vpcArnPattern
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}),
|
|
35
|
+
new PolicyStatement({
|
|
36
|
+
actions: ["ec2:CreateRoute", "ec2:DeleteRoute"],
|
|
37
|
+
resources: ["*"],
|
|
38
|
+
conditions: {
|
|
39
|
+
StringEquals: {
|
|
40
|
+
"ec2:Vpc": vpcArnPattern
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
new PolicyStatement({
|
|
45
|
+
actions: [
|
|
46
|
+
"ec2:DescribeRouteTables",
|
|
47
|
+
"ec2:DescribeVpcPeeringConnections"
|
|
48
|
+
],
|
|
49
|
+
resources: ["*"]
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
this.roleArn = this.role.roleArn;
|
|
56
|
+
Tags.of(this).add("fjall:resource:type", "vpc-peering-accepter");
|
|
57
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.ENVIRONMENT, props.costAllocationEnvironment ?? DEFAULT_COST_ALLOCATION_ENVIRONMENT);
|
|
58
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.SERVICE, "vpcPeeringAccepter");
|
|
59
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.DOMAIN, props.costAllocationDomain ?? props.localVpc.node.id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { CfnVPCPeeringConnection, type IVpc, type SubnetSelection } from "aws-cdk-lib/aws-ec2";
|
|
3
|
+
export interface VpcPeeringConnectionProps {
|
|
4
|
+
/** The local VPC to peer from. */
|
|
5
|
+
readonly localVpc: IVpc;
|
|
6
|
+
/** The local VPC CIDR (destination of the accepter's return routes). */
|
|
7
|
+
readonly localVpcCidr: string;
|
|
8
|
+
/** The remote VPC ID. */
|
|
9
|
+
readonly peerVpcId: string;
|
|
10
|
+
/** The remote VPC CIDR (destination of the local routes). */
|
|
11
|
+
readonly peerVpcCidr: string;
|
|
12
|
+
/** Remote account ID — required for cross-account peering. */
|
|
13
|
+
readonly peerAccountId?: string;
|
|
14
|
+
/** Remote region — required for cross-region peering. */
|
|
15
|
+
readonly peerRegion?: string;
|
|
16
|
+
/** ARN of the accepter role (for auto-accept and cross-account route management). */
|
|
17
|
+
readonly peerRoleArn?: string;
|
|
18
|
+
/** Route-table IDs in the accepter VPC (for cross-account return routes). */
|
|
19
|
+
readonly peerRouteTableIds?: string[];
|
|
20
|
+
/** Local subnet selection for routes. Defaults to `PRIVATE_WITH_EGRESS`. */
|
|
21
|
+
readonly routeSubnets?: SubnetSelection;
|
|
22
|
+
/** Enable DNS resolution across the peering on both sides. Defaults to true. */
|
|
23
|
+
readonly enableDnsResolution?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Optional cross-app label — when present, added as the `fjall:peering:peer-app`
|
|
26
|
+
* tag and used as the default cost-allocation domain.
|
|
27
|
+
*/
|
|
28
|
+
readonly peerAppName?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Optional organisation ID of the remote app — surfaced as a public-readonly
|
|
31
|
+
* property on the construct for downstream consumers (ECS `remoteConnections`)
|
|
32
|
+
* that need to build cross-app SSM paths.
|
|
33
|
+
*/
|
|
34
|
+
readonly peerOrgId?: string;
|
|
35
|
+
/** Cost-allocation override — defaults to `"management"`. */
|
|
36
|
+
readonly costAllocationEnvironment?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Cost-allocation override — defaults to `peerAppName` if provided, otherwise
|
|
39
|
+
* the peer VPC ID.
|
|
40
|
+
*/
|
|
41
|
+
readonly costAllocationDomain?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare class VpcPeeringConnection extends Construct {
|
|
44
|
+
readonly peeringConnectionId: string;
|
|
45
|
+
readonly peering: CfnVPCPeeringConnection;
|
|
46
|
+
readonly peerAppName: string | undefined;
|
|
47
|
+
readonly peerOrgId: string | undefined;
|
|
48
|
+
constructor(scope: Construct, id: string, props: VpcPeeringConnectionProps);
|
|
49
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { Stack, Tags } from "aws-cdk-lib";
|
|
3
|
+
import { CfnRoute, CfnVPCPeeringConnection, SubnetType } from "aws-cdk-lib/aws-ec2";
|
|
4
|
+
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
5
|
+
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from "aws-cdk-lib/custom-resources";
|
|
6
|
+
import { COST_ALLOCATION_TAGS, DEFAULT_COST_ALLOCATION_ENVIRONMENT } from "../../../utils/costAllocationTags.js";
|
|
7
|
+
import { CrossAccountReturnRoutes } from "./crossAccountReturnRoutes.js";
|
|
8
|
+
export class VpcPeeringConnection extends Construct {
|
|
9
|
+
peeringConnectionId;
|
|
10
|
+
peering;
|
|
11
|
+
peerAppName;
|
|
12
|
+
peerOrgId;
|
|
13
|
+
constructor(scope, id, props) {
|
|
14
|
+
super(scope, id);
|
|
15
|
+
this.peerAppName = props.peerAppName;
|
|
16
|
+
this.peerOrgId = props.peerOrgId;
|
|
17
|
+
this.peering = new CfnVPCPeeringConnection(this, "Peering", {
|
|
18
|
+
vpcId: props.localVpc.vpcId,
|
|
19
|
+
peerVpcId: props.peerVpcId,
|
|
20
|
+
peerOwnerId: props.peerAccountId,
|
|
21
|
+
peerRegion: props.peerRegion,
|
|
22
|
+
peerRoleArn: props.peerRoleArn
|
|
23
|
+
});
|
|
24
|
+
this.peeringConnectionId = this.peering.attrId;
|
|
25
|
+
const subnets = props.localVpc.selectSubnets(props.routeSubnets ?? { subnetType: SubnetType.PRIVATE_WITH_EGRESS });
|
|
26
|
+
for (const subnet of subnets.subnets) {
|
|
27
|
+
new CfnRoute(this, `Route${subnet.node.id}`, {
|
|
28
|
+
routeTableId: subnet.routeTable.routeTableId,
|
|
29
|
+
destinationCidrBlock: props.peerVpcCidr,
|
|
30
|
+
vpcPeeringConnectionId: this.peering.attrId
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const enableDnsResolution = props.enableDnsResolution !== false;
|
|
34
|
+
// Requester-side DNS runs in the local account, so a plain AwsCustomResource
|
|
35
|
+
// is sufficient. The accepter side is delegated to the cross-account Lambda.
|
|
36
|
+
if (enableDnsResolution) {
|
|
37
|
+
new AwsCustomResource(this, "EnableRequesterDns", {
|
|
38
|
+
onCreate: {
|
|
39
|
+
service: "EC2",
|
|
40
|
+
action: "modifyVpcPeeringConnectionOptions",
|
|
41
|
+
parameters: {
|
|
42
|
+
VpcPeeringConnectionId: this.peering.attrId,
|
|
43
|
+
RequesterPeeringConnectionOptions: {
|
|
44
|
+
AllowDnsResolutionFromRemoteVpc: true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
physicalResourceId: PhysicalResourceId.of(`${id}-requester-dns`)
|
|
48
|
+
},
|
|
49
|
+
policy: AwsCustomResourcePolicy.fromStatements([
|
|
50
|
+
new PolicyStatement({
|
|
51
|
+
actions: ["ec2:ModifyVpcPeeringConnectionOptions"],
|
|
52
|
+
resources: [
|
|
53
|
+
Stack.of(this).formatArn({
|
|
54
|
+
service: "ec2",
|
|
55
|
+
resource: "vpc-peering-connection",
|
|
56
|
+
resourceName: this.peering.attrId
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
})
|
|
60
|
+
])
|
|
61
|
+
});
|
|
62
|
+
}
|
|
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 &&
|
|
84
|
+
props.peerRouteTableIds.length > 0) {
|
|
85
|
+
new CrossAccountReturnRoutes(this, "ReturnRoutes", {
|
|
86
|
+
peerRoleArn: props.peerRoleArn,
|
|
87
|
+
peerRegion: props.peerRegion,
|
|
88
|
+
routeTableIds: props.peerRouteTableIds,
|
|
89
|
+
localVpcCidr: props.localVpcCidr,
|
|
90
|
+
peeringConnectionId: this.peering.attrId,
|
|
91
|
+
enableDns: enableDnsResolution
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
Tags.of(this).add("fjall:resource:type", "vpc-peering");
|
|
95
|
+
Tags.of(this).add("fjall:peering:peer-vpc", props.peerVpcId);
|
|
96
|
+
if (props.peerAccountId) {
|
|
97
|
+
Tags.of(this).add("fjall:peering:peer-account", props.peerAccountId);
|
|
98
|
+
}
|
|
99
|
+
if (props.peerAppName) {
|
|
100
|
+
Tags.of(this).add("fjall:peering:peer-app", props.peerAppName);
|
|
101
|
+
}
|
|
102
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.ENVIRONMENT, props.costAllocationEnvironment ?? DEFAULT_COST_ALLOCATION_ENVIRONMENT);
|
|
103
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.SERVICE, "vpcPeering");
|
|
104
|
+
Tags.of(this).add(COST_ALLOCATION_TAGS.DOMAIN, props.costAllocationDomain ?? props.peerAppName ?? props.peerVpcId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -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,
|