@composurecdk/ec2 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # @composurecdk/ec2
2
+
3
+ EC2 and VPC builders for [ComposureCDK](../../README.md).
4
+
5
+ This package provides fluent builders for AWS EC2 instances and VPCs with secure, AWS-recommended defaults. It wraps the CDK [Instance](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Instance.html) and [Vpc](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html) constructs — refer to the CDK documentation for the full set of configurable properties.
6
+
7
+ ## Instance Builder
8
+
9
+ ```ts
10
+ import { createInstanceBuilder } from "@composurecdk/ec2";
11
+ import { InstanceClass, InstanceSize, InstanceType, MachineImage } from "aws-cdk-lib/aws-ec2";
12
+
13
+ const server = createInstanceBuilder()
14
+ .vpc(vpc)
15
+ .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
16
+ .machineImage(MachineImage.latestAmazonLinux2023())
17
+ .build(stack, "MyInstance");
18
+ ```
19
+
20
+ Every [InstanceProps](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.InstanceProps.html) property is available as a fluent setter on the builder, except `vpc` which is set via the dedicated `.vpc()` method to support cross-component wiring with `ref<T>(...)`.
21
+
22
+ ## Secure Defaults
23
+
24
+ `createInstanceBuilder` applies the following defaults. Each can be overridden via the builder's fluent API.
25
+
26
+ | Property | Default | Rationale |
27
+ | ----------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
28
+ | `requireImdsv2` | `true` | IMDSv2 requires a session token, blocking the SSRF-based credential exfiltration common to IMDSv1. |
29
+ | `detailedMonitoring` | `true` | 1-minute CloudWatch metric granularity is required for short-window alarm evaluation. |
30
+ | `ssmSessionPermissions` | `true` | Attaches `AmazonSSMManagedInstanceCore` — Session Manager replaces SSH entirely (no key pairs, bastions). |
31
+ | `ebsOptimized` | `true` | Dedicated EBS bandwidth. Free on current-generation instance types. |
32
+ | `blockDevices` | 8 GiB GP3 root volume at `/dev/xvda`, encrypted | Encrypted at rest with the account's default EBS KMS key. |
33
+
34
+ Three properties intentionally have no default — they are application-specific and must be supplied explicitly:
35
+
36
+ - `vpc` (via the `.vpc()` method)
37
+ - `instanceType`
38
+ - `machineImage`
39
+
40
+ The defaults are exported as `INSTANCE_DEFAULTS` for visibility and testing:
41
+
42
+ ```ts
43
+ import { INSTANCE_DEFAULTS } from "@composurecdk/ec2";
44
+ ```
45
+
46
+ ## Recommended Alarms
47
+
48
+ The builder creates [AWS-recommended CloudWatch alarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2) by default. No alarm actions are configured — wire actions via `alarmActionsPolicy` from `@composurecdk/cloudwatch`, or by accessing alarms from the build result.
49
+
50
+ | Alarm | Metric | Default threshold | Created when |
51
+ | ------------------------------ | ---------------------------------------------- | ------------------- | ----------------------------------------------------- |
52
+ | `cpuUtilization` | CPUUtilization (Average, 1 min) | > 80% over 5 min | Always |
53
+ | `statusCheckFailed` | StatusCheckFailed (Sum, 1 min) | > 0 over 2 min | Always |
54
+ | `attachedEbsStatusCheckFailed` | StatusCheckFailed_AttachedEBS (Maximum, 1 min) | >= 1 over 10 min | Always |
55
+ | `cpuCreditBalance` | CPUCreditBalance (Minimum, 5 min) | < 50 over 3 x 5 min | `instanceType` is burstable (T2, T3, T3a, T4g family) |
56
+
57
+ The defaults are exported as `INSTANCE_ALARM_DEFAULTS` for visibility and testing:
58
+
59
+ ```ts
60
+ import { INSTANCE_ALARM_DEFAULTS } from "@composurecdk/ec2";
61
+ ```
62
+
63
+ ### Customizing thresholds
64
+
65
+ Override individual alarm properties via `recommendedAlarms`. Unspecified fields keep their defaults.
66
+
67
+ ```ts
68
+ const server = createInstanceBuilder()
69
+ .vpc(vpc)
70
+ .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
71
+ .machineImage(MachineImage.latestAmazonLinux2023())
72
+ .recommendedAlarms({
73
+ cpuUtilization: { threshold: 90, evaluationPeriods: 3, datapointsToAlarm: 3 },
74
+ });
75
+ ```
76
+
77
+ ### Disabling alarms
78
+
79
+ Disable all recommended alarms:
80
+
81
+ ```ts
82
+ builder.recommendedAlarms(false);
83
+ // or
84
+ builder.recommendedAlarms({ enabled: false });
85
+ ```
86
+
87
+ Disable individual alarms:
88
+
89
+ ```ts
90
+ builder.recommendedAlarms({ cpuCreditBalance: false });
91
+ ```
92
+
93
+ ### Custom alarms
94
+
95
+ Add custom alarms alongside the recommended ones via `addAlarm`. The callback receives an `AlarmDefinitionBuilder` typed to the `Instance`.
96
+
97
+ ```ts
98
+ import { Metric, Stats } from "aws-cdk-lib/aws-cloudwatch";
99
+ import { Duration } from "aws-cdk-lib";
100
+
101
+ const server = createInstanceBuilder()
102
+ .vpc(vpc)
103
+ .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
104
+ .machineImage(MachineImage.latestAmazonLinux2023())
105
+ .addAlarm("networkIn", (alarm) =>
106
+ alarm
107
+ .metric(
108
+ (instance) =>
109
+ new Metric({
110
+ namespace: "AWS/EC2",
111
+ metricName: "NetworkIn",
112
+ dimensionsMap: { InstanceId: instance.instanceId },
113
+ statistic: Stats.AVERAGE,
114
+ period: Duration.minutes(1),
115
+ }),
116
+ )
117
+ .threshold(1_000_000_000)
118
+ .greaterThanOrEqual()
119
+ .description("Inbound network traffic is unusually high"),
120
+ );
121
+ ```
122
+
123
+ ## VPC Builder
124
+
125
+ ```ts
126
+ import { createVpcBuilder } from "@composurecdk/ec2";
127
+
128
+ const network = createVpcBuilder().maxAzs(3).natGateways(3).build(stack, "Network");
129
+ ```
130
+
131
+ Every [VpcProps](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.VpcProps.html) property is available as a fluent setter on the builder.
132
+
133
+ ### VPC Defaults
134
+
135
+ | Property | Default | Rationale |
136
+ | ------------------------------ | --------------------------------- | -------------------------------------------------------------------------------------------------- |
137
+ | `maxAzs` | `2` | Meaningful HA without overspending. Override to 3+ for stricter production guarantees. |
138
+ | `natGateways` | `1` | Cost-conscious default. Production HA workloads should set `natGateways` to match `maxAzs`. |
139
+ | `enableDnsSupport` | `true` | Required for most AWS managed services (ALB, RDS, VPC endpoints). |
140
+ | `enableDnsHostnames` | `true` | Required for instances to receive public DNS hostnames. |
141
+ | `restrictDefaultSecurityGroup` | `true` | Strips rules from the default SG, forcing explicit SG design. |
142
+ | Flow logs | Auto-created CloudWatch log group | Network audit trail with well-architected retention and removal policies via `@composurecdk/logs`. |
143
+
144
+ The defaults are exported as `VPC_DEFAULTS` for visibility and testing:
145
+
146
+ ```ts
147
+ import { VPC_DEFAULTS } from "@composurecdk/ec2";
148
+ ```
149
+
150
+ ### Flow logs
151
+
152
+ By default, the builder auto-creates a CloudWatch-Logs-backed flow log with a managed `LogGroup` from `@composurecdk/logs` (two-year retention, `RemovalPolicy.RETAIN`).
153
+
154
+ Customize the auto-created LogGroup:
155
+
156
+ ```ts
157
+ createVpcBuilder().flowLogs({
158
+ configure: (lg) => lg.retention(RetentionDays.NINETY_DAYS).removalPolicy(RemovalPolicy.DESTROY),
159
+ });
160
+ ```
161
+
162
+ Use a user-managed destination (e.g. an S3 bucket):
163
+
164
+ ```ts
165
+ createVpcBuilder().flowLogs({
166
+ destination: FlowLogDestination.toS3(myBucket),
167
+ });
168
+ ```
169
+
170
+ Disable flow logs entirely:
171
+
172
+ ```ts
173
+ createVpcBuilder().flowLogs(false);
174
+ ```
175
+
176
+ For multiple flow logs against the same VPC, omit this config and create additional `FlowLog` constructs directly against the returned `vpc`.
177
+
178
+ ## Composing EC2 + VPC
179
+
180
+ Compose the builders into a single system — the instance is wired to the VPC via `ref`:
181
+
182
+ ```ts
183
+ import { compose, ref } from "@composurecdk/core";
184
+ import { createInstanceBuilder, createVpcBuilder, type VpcBuilderResult } from "@composurecdk/ec2";
185
+ import type { Vpc } from "aws-cdk-lib/aws-ec2";
186
+
187
+ compose(
188
+ {
189
+ network: createVpcBuilder(),
190
+ server: createInstanceBuilder()
191
+ .vpc(ref<VpcBuilderResult>("network").map((r): Vpc => r.vpc))
192
+ .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
193
+ .machineImage(MachineImage.latestAmazonLinux2023()),
194
+ },
195
+ { network: [], server: ["network"] },
196
+ ).build(stack, "Ec2App");
197
+ ```
198
+
199
+ ## Examples
200
+
201
+ - [Ec2Stack](../examples/src/ec2-app.ts) — VPC + EC2 instance with alarms wired to an SNS topic via `alarmActionsPolicy`.
@@ -0,0 +1,7 @@
1
+ export { createInstanceBuilder, type IInstanceBuilder, type InstanceBuilderProps, type InstanceBuilderResult, } from "./instance-builder.js";
2
+ export { INSTANCE_DEFAULTS } from "./instance-defaults.js";
3
+ export { type InstanceAlarmConfig } from "./instance-alarm-config.js";
4
+ export { INSTANCE_ALARM_DEFAULTS } from "./instance-alarm-defaults.js";
5
+ export { createVpcBuilder, type FlowLogsConfig, type IVpcBuilder, type VpcBuilderProps, type VpcBuilderResult, } from "./vpc-builder.js";
6
+ export { VPC_DEFAULTS } from "./vpc-defaults.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EACL,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { createInstanceBuilder, } from "./instance-builder.js";
2
+ export { INSTANCE_DEFAULTS } from "./instance-defaults.js";
3
+ export { INSTANCE_ALARM_DEFAULTS } from "./instance-alarm-defaults.js";
4
+ export { createVpcBuilder, } from "./vpc-builder.js";
5
+ export { VPC_DEFAULTS } from "./vpc-defaults.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,GAItB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EACL,gBAAgB,GAKjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { AlarmConfig } from "@composurecdk/cloudwatch";
2
+ /**
3
+ * Controls which recommended alarms are created for an EC2 instance.
4
+ * All alarms are enabled by default with AWS-recommended thresholds.
5
+ * Set individual alarms to `false` to disable them, or provide an
6
+ * {@link AlarmConfig} to tune thresholds.
7
+ *
8
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
9
+ */
10
+ export interface InstanceAlarmConfig {
11
+ /**
12
+ * Master switch: set to `false` to disable all recommended alarms.
13
+ * Individual alarms can also be disabled via their own entry.
14
+ * @default true
15
+ */
16
+ enabled?: boolean;
17
+ /**
18
+ * Alarm when CPU utilization is sustained at a high level.
19
+ *
20
+ * Metric: `AWS/EC2 CPUUtilization`, statistic Average, period 1 minute.
21
+ * Default threshold: > 80% over 5 consecutive minutes.
22
+ *
23
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
24
+ */
25
+ cpuUtilization?: AlarmConfig | false;
26
+ /**
27
+ * Alarm when the instance fails its EC2 or system status checks.
28
+ *
29
+ * Metric: `AWS/EC2 StatusCheckFailed`, statistic Sum, period 1 minute.
30
+ * Default threshold: > 0 failures over 2 consecutive minutes.
31
+ *
32
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
33
+ */
34
+ statusCheckFailed?: AlarmConfig | false;
35
+ /**
36
+ * Alarm when the instance's attached EBS volumes are unreachable or
37
+ * unable to complete I/O — typically a host or storage-subsystem issue.
38
+ *
39
+ * Metric: `AWS/EC2 StatusCheckFailed_AttachedEBS`, statistic Maximum,
40
+ * period 1 minute. Default threshold: >= 1 over 10 consecutive minutes
41
+ * (the longer window reflects that EBS infrastructure usually self-heals
42
+ * within a few minutes).
43
+ *
44
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
45
+ */
46
+ attachedEbsStatusCheckFailed?: AlarmConfig | false;
47
+ /**
48
+ * Alarm when burstable (T-family) CPU credit balance falls low,
49
+ * indicating the instance is about to be throttled to baseline.
50
+ *
51
+ * Only created when the `instanceType` family is one of: t2, t3, t3a, t4g.
52
+ * For other instance types this alarm is skipped entirely.
53
+ *
54
+ * Metric: `AWS/EC2 CPUCreditBalance`, statistic Minimum, period 5 minutes.
55
+ * Default threshold: < 50 credits over 3 consecutive 5-minute windows.
56
+ *
57
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
58
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-credits-baseline-concepts.html
59
+ */
60
+ cpuCreditBalance?: AlarmConfig | false;
61
+ }
62
+ //# sourceMappingURL=instance-alarm-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarm-config.d.ts","sourceRoot":"","sources":["../src/instance-alarm-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAErC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAExC;;;;;;;;;;OAUG;IACH,4BAA4B,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEnD;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CACxC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=instance-alarm-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarm-config.js","sourceRoot":"","sources":["../src/instance-alarm-config.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { AlarmConfigDefaults } from "@composurecdk/cloudwatch";
2
+ interface InstanceAlarmDefaults {
3
+ enabled: true;
4
+ cpuUtilization: AlarmConfigDefaults;
5
+ statusCheckFailed: AlarmConfigDefaults;
6
+ attachedEbsStatusCheckFailed: AlarmConfigDefaults;
7
+ cpuCreditBalance: AlarmConfigDefaults;
8
+ }
9
+ /**
10
+ * AWS-recommended default alarm configuration for EC2 instances.
11
+ *
12
+ * Thresholds are sourced from the CloudWatch Best Practice Recommended
13
+ * Alarms guide. Thresholds may reasonably be tuned per-workload; defaults
14
+ * bias toward catching obvious issues without excessive noise.
15
+ *
16
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
17
+ */
18
+ export declare const INSTANCE_ALARM_DEFAULTS: InstanceAlarmDefaults;
19
+ export {};
20
+ //# sourceMappingURL=instance-alarm-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarm-defaults.d.ts","sourceRoot":"","sources":["../src/instance-alarm-defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,cAAc,EAAE,mBAAmB,CAAC;IACpC,iBAAiB,EAAE,mBAAmB,CAAC;IACvC,4BAA4B,EAAE,mBAAmB,CAAC;IAClD,gBAAgB,EAAE,mBAAmB,CAAC;CACvC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,qBAsDrC,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { TreatMissingData } from "aws-cdk-lib/aws-cloudwatch";
2
+ /**
3
+ * AWS-recommended default alarm configuration for EC2 instances.
4
+ *
5
+ * Thresholds are sourced from the CloudWatch Best Practice Recommended
6
+ * Alarms guide. Thresholds may reasonably be tuned per-workload; defaults
7
+ * bias toward catching obvious issues without excessive noise.
8
+ *
9
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
10
+ */
11
+ export const INSTANCE_ALARM_DEFAULTS = {
12
+ enabled: true,
13
+ /**
14
+ * Sustained high CPU indicates the instance is a bottleneck and may
15
+ * need to be scaled up. 80% over 5 consecutive minutes avoids
16
+ * alarming on brief workload spikes.
17
+ */
18
+ cpuUtilization: {
19
+ threshold: 80,
20
+ evaluationPeriods: 5,
21
+ datapointsToAlarm: 5,
22
+ treatMissingData: TreatMissingData.NOT_BREACHING,
23
+ },
24
+ /**
25
+ * Any status check failure is actionable — it indicates instance or
26
+ * host impairment. 2-of-2 evaluation filters transient single-minute
27
+ * noise while keeping time-to-detect low.
28
+ */
29
+ statusCheckFailed: {
30
+ threshold: 0,
31
+ evaluationPeriods: 2,
32
+ datapointsToAlarm: 2,
33
+ treatMissingData: TreatMissingData.NOT_BREACHING,
34
+ },
35
+ /**
36
+ * Attached EBS volumes are unreachable or unable to complete I/O —
37
+ * typically a host or storage-subsystem issue. The 10-of-10 evaluation
38
+ * window matches AWS guidance: EBS infrastructure usually self-heals
39
+ * within a few minutes, so a longer window avoids paging on transient
40
+ * issues that resolve without intervention.
41
+ */
42
+ attachedEbsStatusCheckFailed: {
43
+ threshold: 1,
44
+ evaluationPeriods: 10,
45
+ datapointsToAlarm: 10,
46
+ treatMissingData: TreatMissingData.NOT_BREACHING,
47
+ },
48
+ /**
49
+ * Low CPU credit balance on burstable instances means imminent
50
+ * throttling to baseline performance. Threshold < 50 at 5-minute
51
+ * minimum gives an early warning to investigate or switch instance
52
+ * family. Credit balance metrics are only emitted at 5-minute
53
+ * granularity regardless of detailed monitoring.
54
+ */
55
+ cpuCreditBalance: {
56
+ threshold: 50,
57
+ evaluationPeriods: 3,
58
+ datapointsToAlarm: 3,
59
+ treatMissingData: TreatMissingData.NOT_BREACHING,
60
+ },
61
+ };
62
+ //# sourceMappingURL=instance-alarm-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarm-defaults.js","sourceRoot":"","sources":["../src/instance-alarm-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAW9D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D,OAAO,EAAE,IAAI;IAEb;;;;OAIG;IACH,cAAc,EAAE;QACd,SAAS,EAAE,EAAE;QACb,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED;;;;OAIG;IACH,iBAAiB,EAAE;QACjB,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED;;;;;;OAMG;IACH,4BAA4B,EAAE;QAC5B,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,EAAE;QACrB,iBAAiB,EAAE,EAAE;QACrB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;IAED;;;;;;OAMG;IACH,gBAAgB,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,gBAAgB,CAAC,aAAa;KACjD;CACF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type Alarm } from "aws-cdk-lib/aws-cloudwatch";
2
+ import type { Instance, InstanceProps } from "aws-cdk-lib/aws-ec2";
3
+ import type { IConstruct } from "constructs";
4
+ import type { AlarmDefinition } from "@composurecdk/cloudwatch";
5
+ import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
6
+ import type { InstanceAlarmConfig } from "./instance-alarm-config.js";
7
+ /**
8
+ * Resolves the recommended alarm configuration into fully-resolved
9
+ * {@link AlarmDefinition}s, applying contextual logic for the
10
+ * burstable-only CPU credit alarm.
11
+ */
12
+ export declare function resolveInstanceAlarmDefinitions(instance: Instance, config: InstanceAlarmConfig | undefined, props: Pick<InstanceProps, "instanceType">): AlarmDefinition[];
13
+ /**
14
+ * Creates AWS-recommended CloudWatch alarms for an EC2 instance,
15
+ * merging recommended definitions with any custom alarm builders.
16
+ *
17
+ * @param scope - CDK construct scope for creating alarm constructs.
18
+ * @param id - Base identifier for alarm construct ids.
19
+ * @param instance - The EC2 instance to create alarms for.
20
+ * @param config - User-provided alarm configuration, or `false` to disable all.
21
+ * @param props - The merged instance props, used for contextual alarm thresholds.
22
+ * @param customAlarms - Custom alarm builders added via `addAlarm()`.
23
+ * @returns A record mapping alarm keys to their created Alarm constructs.
24
+ *
25
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
26
+ */
27
+ export declare function createInstanceAlarms(scope: IConstruct, id: string, instance: Instance, config: InstanceAlarmConfig | false | undefined, props: Pick<InstanceProps, "instanceType">, customAlarms?: AlarmDefinitionBuilder<Instance>[]): Record<string, Alarm>;
28
+ //# sourceMappingURL=instance-alarms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarms.d.ts","sourceRoot":"","sources":["../src/instance-alarms.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAqC,MAAM,4BAA4B,CAAC;AAC3F,OAAO,KAAK,EAAa,QAAQ,EAAE,aAAa,EAAgB,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAoC,MAAM,0BAA0B,CAAC;AACpG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AA6CtE;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,mBAAmB,GAAG,SAAS,EACvC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,GACzC,eAAe,EAAE,CA2EnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,mBAAmB,GAAG,KAAK,GAAG,SAAS,EAC/C,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,EAC1C,YAAY,GAAE,sBAAsB,CAAC,QAAQ,CAAC,EAAO,GACpD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAUvB"}
@@ -0,0 +1,128 @@
1
+ import { Duration } from "aws-cdk-lib";
2
+ import { ComparisonOperator, Metric, Stats } from "aws-cdk-lib/aws-cloudwatch";
3
+ import { createAlarms, resolveAlarmConfig } from "@composurecdk/cloudwatch";
4
+ import { INSTANCE_ALARM_DEFAULTS } from "./instance-alarm-defaults.js";
5
+ const METRIC_PERIOD = Duration.minutes(1);
6
+ const METRIC_PERIOD_LABEL = `${String(METRIC_PERIOD.toMinutes())} minute`;
7
+ /**
8
+ * CPU credit metrics are emitted by EC2 at 5-minute granularity regardless
9
+ * of whether detailed monitoring is enabled. Using a shorter period yields
10
+ * missing data rather than higher resolution.
11
+ *
12
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_credits_CPU.html
13
+ */
14
+ const CREDIT_METRIC_PERIOD = Duration.minutes(5);
15
+ const CREDIT_METRIC_PERIOD_LABEL = `${String(CREDIT_METRIC_PERIOD.toMinutes())} minute`;
16
+ /**
17
+ * Instance type family prefixes that accrue CPU credits (burstable).
18
+ * Used to decide whether to emit the contextual {@link InstanceAlarmConfig.cpuCreditBalance}
19
+ * alarm. Other families bill at a flat CPU rate and have no credit metric.
20
+ *
21
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances.html
22
+ */
23
+ const BURSTABLE_FAMILY_PREFIXES = ["t2.", "t3.", "t3a.", "t4g."];
24
+ function isBurstableInstanceType(instanceType) {
25
+ const identifier = instanceType.toString();
26
+ return BURSTABLE_FAMILY_PREFIXES.some((prefix) => identifier.startsWith(prefix));
27
+ }
28
+ function instanceMetric(instance, metricName, statistic, period = METRIC_PERIOD) {
29
+ return new Metric({
30
+ namespace: "AWS/EC2",
31
+ metricName,
32
+ dimensionsMap: { InstanceId: instance.instanceId },
33
+ statistic,
34
+ period,
35
+ });
36
+ }
37
+ /**
38
+ * Resolves the recommended alarm configuration into fully-resolved
39
+ * {@link AlarmDefinition}s, applying contextual logic for the
40
+ * burstable-only CPU credit alarm.
41
+ */
42
+ export function resolveInstanceAlarmDefinitions(instance, config, props) {
43
+ if (config?.enabled === false)
44
+ return [];
45
+ const definitions = [];
46
+ if (config?.cpuUtilization !== false) {
47
+ const cfg = resolveAlarmConfig(config?.cpuUtilization, INSTANCE_ALARM_DEFAULTS.cpuUtilization);
48
+ definitions.push({
49
+ key: "cpuUtilization",
50
+ alarmName: cfg.alarmName,
51
+ metric: instanceMetric(instance, "CPUUtilization", Stats.AVERAGE),
52
+ threshold: cfg.threshold,
53
+ comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
54
+ evaluationPeriods: cfg.evaluationPeriods,
55
+ datapointsToAlarm: cfg.datapointsToAlarm,
56
+ treatMissingData: cfg.treatMissingData,
57
+ description: `EC2 instance CPU utilization is sustained at a high level. Threshold: > ${String(cfg.threshold)}% average over ${String(cfg.evaluationPeriods)} x ${METRIC_PERIOD_LABEL}.`,
58
+ });
59
+ }
60
+ if (config?.statusCheckFailed !== false) {
61
+ const cfg = resolveAlarmConfig(config?.statusCheckFailed, INSTANCE_ALARM_DEFAULTS.statusCheckFailed);
62
+ definitions.push({
63
+ key: "statusCheckFailed",
64
+ alarmName: cfg.alarmName,
65
+ metric: instanceMetric(instance, "StatusCheckFailed", Stats.SUM),
66
+ threshold: cfg.threshold,
67
+ comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
68
+ evaluationPeriods: cfg.evaluationPeriods,
69
+ datapointsToAlarm: cfg.datapointsToAlarm,
70
+ treatMissingData: cfg.treatMissingData,
71
+ description: `EC2 instance is failing its status checks. Threshold: > ${String(cfg.threshold)} failed checks over ${String(cfg.evaluationPeriods)} x ${METRIC_PERIOD_LABEL}.`,
72
+ });
73
+ }
74
+ if (config?.attachedEbsStatusCheckFailed !== false) {
75
+ const cfg = resolveAlarmConfig(config?.attachedEbsStatusCheckFailed, INSTANCE_ALARM_DEFAULTS.attachedEbsStatusCheckFailed);
76
+ definitions.push({
77
+ key: "attachedEbsStatusCheckFailed",
78
+ alarmName: cfg.alarmName,
79
+ metric: instanceMetric(instance, "StatusCheckFailed_AttachedEBS", Stats.MAXIMUM),
80
+ threshold: cfg.threshold,
81
+ comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
82
+ evaluationPeriods: cfg.evaluationPeriods,
83
+ datapointsToAlarm: cfg.datapointsToAlarm,
84
+ treatMissingData: cfg.treatMissingData,
85
+ description: `EC2 instance attached EBS volume(s) are unreachable or unable to complete I/O. Threshold: >= ${String(cfg.threshold)} failed checks (max) over ${String(cfg.evaluationPeriods)} x ${METRIC_PERIOD_LABEL}.`,
86
+ });
87
+ }
88
+ if (config?.cpuCreditBalance !== false && isBurstableInstanceType(props.instanceType)) {
89
+ const cfg = resolveAlarmConfig(config?.cpuCreditBalance, INSTANCE_ALARM_DEFAULTS.cpuCreditBalance);
90
+ definitions.push({
91
+ key: "cpuCreditBalance",
92
+ alarmName: cfg.alarmName,
93
+ metric: instanceMetric(instance, "CPUCreditBalance", Stats.MINIMUM, CREDIT_METRIC_PERIOD),
94
+ threshold: cfg.threshold,
95
+ comparisonOperator: ComparisonOperator.LESS_THAN_THRESHOLD,
96
+ evaluationPeriods: cfg.evaluationPeriods,
97
+ datapointsToAlarm: cfg.datapointsToAlarm,
98
+ treatMissingData: cfg.treatMissingData,
99
+ description: `EC2 burstable instance CPU credit balance is low — baseline throttling is imminent. Threshold: < ${String(cfg.threshold)} credits (minimum) over ${String(cfg.evaluationPeriods)} x ${CREDIT_METRIC_PERIOD_LABEL}.`,
100
+ });
101
+ }
102
+ return definitions;
103
+ }
104
+ /**
105
+ * Creates AWS-recommended CloudWatch alarms for an EC2 instance,
106
+ * merging recommended definitions with any custom alarm builders.
107
+ *
108
+ * @param scope - CDK construct scope for creating alarm constructs.
109
+ * @param id - Base identifier for alarm construct ids.
110
+ * @param instance - The EC2 instance to create alarms for.
111
+ * @param config - User-provided alarm configuration, or `false` to disable all.
112
+ * @param props - The merged instance props, used for contextual alarm thresholds.
113
+ * @param customAlarms - Custom alarm builders added via `addAlarm()`.
114
+ * @returns A record mapping alarm keys to their created Alarm constructs.
115
+ *
116
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
117
+ */
118
+ export function createInstanceAlarms(scope, id, instance, config, props, customAlarms = []) {
119
+ if (config === false)
120
+ return {};
121
+ const enabled = config?.enabled ?? INSTANCE_ALARM_DEFAULTS.enabled;
122
+ if (!enabled)
123
+ return {};
124
+ const recommended = resolveInstanceAlarmDefinitions(instance, config, props);
125
+ const custom = customAlarms.map((b) => b.resolve(instance));
126
+ return createAlarms(scope, id, [...recommended, ...custom]);
127
+ }
128
+ //# sourceMappingURL=instance-alarms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-alarms.js","sourceRoot":"","sources":["../src/instance-alarms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ import { type Alarm } from "aws-cdk-lib/aws-cloudwatch";
2
+ import { Instance, type IKeyPair, type ISecurityGroup, type IVpc, type InstanceProps } from "aws-cdk-lib/aws-ec2";
3
+ import { type IRole } from "aws-cdk-lib/aws-iam";
4
+ import { type IConstruct } from "constructs";
5
+ import { type IBuilder, type Lifecycle, type Resolvable } from "@composurecdk/core";
6
+ import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
7
+ import type { InstanceAlarmConfig } from "./instance-alarm-config.js";
8
+ /**
9
+ * Configuration properties for the EC2 instance builder.
10
+ *
11
+ * Extends the CDK {@link InstanceProps} but lifts the cross-component-wiring
12
+ * props to {@link Resolvable} so they can be supplied as either concrete
13
+ * values or {@link Ref}s to sibling components in a {@link compose}d system:
14
+ *
15
+ * - `vpc` is supplied via the dedicated
16
+ * {@link IInstanceBuilder.vpc | .vpc()} method.
17
+ * - `role`, `keyPair`, and `securityGroup` are exposed on the builder as
18
+ * `Resolvable<T>` setters.
19
+ *
20
+ * Other props (`instanceType`, `machineImage`, `userData`, `blockDevices`,
21
+ * etc.) are passed through with their CDK types unchanged because they are
22
+ * almost always constructed inline rather than referenced from another
23
+ * component.
24
+ */
25
+ export interface InstanceBuilderProps extends Omit<InstanceProps, "vpc" | "role" | "keyPair" | "securityGroup"> {
26
+ /**
27
+ * IAM role assumed by the instance via its instance profile.
28
+ *
29
+ * Accepts a concrete {@link IRole} or a {@link Ref} that resolves to one
30
+ * at build time, e.g. a sibling `RoleBuilder` in the same composed system.
31
+ *
32
+ * @default - CDK creates a role and attaches `AmazonSSMManagedInstanceCore`,
33
+ * driven by the `ssmSessionPermissions: true` default in
34
+ * {@link INSTANCE_DEFAULTS}.
35
+ */
36
+ role?: Resolvable<IRole>;
37
+ /**
38
+ * Key pair to associate with the instance.
39
+ *
40
+ * Accepts a concrete {@link IKeyPair} or a {@link Ref} that resolves to
41
+ * one at build time.
42
+ *
43
+ * @default - no key pair is associated; SSM Session Manager is the
44
+ * recommended access path.
45
+ */
46
+ keyPair?: Resolvable<IKeyPair>;
47
+ /**
48
+ * Primary security group for the instance.
49
+ *
50
+ * Accepts a concrete {@link ISecurityGroup} or a {@link Ref} that resolves
51
+ * to one at build time. Additional security groups can be attached via
52
+ * `instance.addSecurityGroup()` after build.
53
+ *
54
+ * @default - CDK creates a security group allowing all outbound traffic.
55
+ */
56
+ securityGroup?: Resolvable<ISecurityGroup>;
57
+ /**
58
+ * Configuration for AWS-recommended CloudWatch alarms.
59
+ *
60
+ * By default, the builder creates recommended alarms with sensible
61
+ * thresholds for every applicable metric. Individual alarms can be
62
+ * customized or disabled. Set to `false` to disable all alarms.
63
+ *
64
+ * No alarm actions are configured by default since notification methods
65
+ * are user-specific. Access alarms from the build result or use an
66
+ * `afterBuild` hook to apply actions.
67
+ *
68
+ * Contextual alarms (`cpuCreditBalance`) are only created when the
69
+ * corresponding instance configuration is present — e.g., burstable
70
+ * T-family instance types.
71
+ *
72
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
73
+ */
74
+ recommendedAlarms?: InstanceAlarmConfig | false;
75
+ }
76
+ /**
77
+ * The build output of a {@link IInstanceBuilder}. Contains the CDK
78
+ * constructs created during {@link Lifecycle.build}, keyed by role.
79
+ */
80
+ export interface InstanceBuilderResult {
81
+ instance: Instance;
82
+ /**
83
+ * CloudWatch alarms created for the instance, keyed by alarm name.
84
+ *
85
+ * Includes both AWS-recommended alarms and any custom alarms added
86
+ * via {@link IInstanceBuilder.addAlarm}. Access individual alarms by
87
+ * key (e.g., `result.alarms.cpuUtilization`).
88
+ *
89
+ * No alarm actions are configured — apply them via the result or an
90
+ * `afterBuild` hook.
91
+ *
92
+ * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#EC2
93
+ */
94
+ alarms: Record<string, Alarm>;
95
+ }
96
+ /**
97
+ * A fluent builder for configuring and creating an AWS EC2 instance.
98
+ *
99
+ * Each configuration property from the CDK {@link InstanceProps} is exposed
100
+ * as an overloaded method: call with a value to set it (returns the builder
101
+ * for chaining), or call with no arguments to read the current value.
102
+ *
103
+ * The `vpc` is set via the dedicated {@link IInstanceBuilder.vpc | .vpc()}
104
+ * method that accepts a {@link Resolvable} value for cross-component wiring
105
+ * (e.g., to a sibling {@link IVpcBuilder}). The `role`, `keyPair`, and
106
+ * `securityGroup` setters likewise accept {@link Resolvable} values so they
107
+ * can be supplied by sibling builders' outputs via {@link ref}.
108
+ *
109
+ * The builder implements {@link Lifecycle}, so it can be used directly as a
110
+ * component in a {@link compose | composed system}. When built, it creates
111
+ * an EC2 instance with the configured properties and returns an
112
+ * {@link InstanceBuilderResult}.
113
+ *
114
+ * AWS-recommended CloudWatch alarms are created by default. Alarms can be
115
+ * customized or disabled via the `recommendedAlarms` property. Custom
116
+ * alarms can be added via the {@link addAlarm} method.
117
+ *
118
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2-readme.html
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const server = createInstanceBuilder()
123
+ * .vpc(vpc)
124
+ * .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
125
+ * .machineImage(MachineImage.latestAmazonLinux2023());
126
+ * ```
127
+ */
128
+ export type IInstanceBuilder = IBuilder<InstanceBuilderProps, InstanceBuilder>;
129
+ declare class InstanceBuilder implements Lifecycle<InstanceBuilderResult> {
130
+ #private;
131
+ props: Partial<InstanceBuilderProps>;
132
+ /**
133
+ * Sets the VPC the instance will be launched into.
134
+ *
135
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
136
+ * at build time. This is how cross-component wiring works — e.g., to a
137
+ * sibling {@link IVpcBuilder} in the same composed system.
138
+ *
139
+ * @param vpc - The VPC or a Ref to one.
140
+ * @returns This builder for chaining.
141
+ */
142
+ vpc(vpc: Resolvable<IVpc>): this;
143
+ /**
144
+ * Adds a custom CloudWatch alarm to be created alongside the recommended
145
+ * alarms. The provided callback receives an {@link AlarmDefinitionBuilder}
146
+ * scoped to the built {@link Instance}; configure it fluently and return it.
147
+ *
148
+ * @param key - A unique key for the alarm (used to generate the alarm id).
149
+ * @param configure - Callback that configures the alarm definition.
150
+ * @returns This builder for chaining.
151
+ */
152
+ addAlarm(key: string, configure: (alarm: AlarmDefinitionBuilder<Instance>) => AlarmDefinitionBuilder<Instance>): this;
153
+ build(scope: IConstruct, id: string, context?: Record<string, object>): InstanceBuilderResult;
154
+ }
155
+ /**
156
+ * Creates a new {@link IInstanceBuilder} for configuring an AWS EC2 instance.
157
+ *
158
+ * This is the entry point for defining an EC2 instance component. The
159
+ * returned builder exposes every {@link InstanceBuilderProps} property as a
160
+ * fluent setter/getter, plus {@link IInstanceBuilder.vpc | .vpc()} for
161
+ * cross-component VPC wiring with Ref support. It implements
162
+ * {@link Lifecycle} for use with {@link compose}.
163
+ *
164
+ * @returns A fluent builder for an AWS EC2 instance.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * const server = createInstanceBuilder()
169
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
170
+ * .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
171
+ * .machineImage(MachineImage.latestAmazonLinux2023());
172
+ *
173
+ * // Use standalone:
174
+ * const result = server.build(stack, "MyInstance");
175
+ *
176
+ * // Or compose into a system:
177
+ * const system = compose(
178
+ * { network: createVpcBuilder(), server },
179
+ * { network: [], server: ["network"] },
180
+ * );
181
+ * ```
182
+ */
183
+ export declare function createInstanceBuilder(): IInstanceBuilder;
184
+ export {};
185
+ //# sourceMappingURL=instance-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-builder.d.ts","sourceRoot":"","sources":["../src/instance-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,IAAI,EACT,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAItE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAChD,aAAa,EACb,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,eAAe,CAC7C;IACC;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAEzB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE/B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IAE3C;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;AAE/E,cAAM,eAAgB,YAAW,SAAS,CAAC,qBAAqB,CAAC;;IAC/D,KAAK,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAM;IAI1C;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI;IAKhC;;;;;;;;OAQG;IACH,QAAQ,CACN,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,KAAK,EAAE,sBAAsB,CAAC,QAAQ,CAAC,KAAK,sBAAsB,CAAC,QAAQ,CAAC,GACvF,IAAI;IAKP,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,qBAAqB;CAuC9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAExD"}
@@ -0,0 +1,87 @@
1
+ import { Instance, } from "aws-cdk-lib/aws-ec2";
2
+ import { Builder, resolve, } from "@composurecdk/core";
3
+ import { AlarmDefinitionBuilder } from "@composurecdk/cloudwatch";
4
+ import { createInstanceAlarms } from "./instance-alarms.js";
5
+ import { INSTANCE_DEFAULTS } from "./instance-defaults.js";
6
+ class InstanceBuilder {
7
+ props = {};
8
+ #customAlarms = [];
9
+ #vpc;
10
+ /**
11
+ * Sets the VPC the instance will be launched into.
12
+ *
13
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
14
+ * at build time. This is how cross-component wiring works — e.g., to a
15
+ * sibling {@link IVpcBuilder} in the same composed system.
16
+ *
17
+ * @param vpc - The VPC or a Ref to one.
18
+ * @returns This builder for chaining.
19
+ */
20
+ vpc(vpc) {
21
+ this.#vpc = vpc;
22
+ return this;
23
+ }
24
+ /**
25
+ * Adds a custom CloudWatch alarm to be created alongside the recommended
26
+ * alarms. The provided callback receives an {@link AlarmDefinitionBuilder}
27
+ * scoped to the built {@link Instance}; configure it fluently and return it.
28
+ *
29
+ * @param key - A unique key for the alarm (used to generate the alarm id).
30
+ * @param configure - Callback that configures the alarm definition.
31
+ * @returns This builder for chaining.
32
+ */
33
+ addAlarm(key, configure) {
34
+ this.#customAlarms.push(configure(new AlarmDefinitionBuilder(key)));
35
+ return this;
36
+ }
37
+ build(scope, id, context) {
38
+ const resolvedVpc = this.#vpc ? resolve(this.#vpc, context) : undefined;
39
+ if (!resolvedVpc) {
40
+ throw new Error(`InstanceBuilder "${id}" requires a VPC. Call .vpc() with an IVpc or a Ref to one.`);
41
+ }
42
+ const { recommendedAlarms: alarmConfig, role, keyPair, securityGroup, ...instanceProps } = this.props;
43
+ const mergedProps = {
44
+ ...INSTANCE_DEFAULTS,
45
+ ...instanceProps,
46
+ vpc: resolvedVpc,
47
+ ...(role !== undefined ? { role: resolve(role, context) } : {}),
48
+ ...(keyPair !== undefined ? { keyPair: resolve(keyPair, context) } : {}),
49
+ ...(securityGroup !== undefined ? { securityGroup: resolve(securityGroup, context) } : {}),
50
+ };
51
+ const instance = new Instance(scope, id, mergedProps);
52
+ const alarms = createInstanceAlarms(scope, id, instance, alarmConfig, mergedProps, this.#customAlarms);
53
+ return { instance, alarms };
54
+ }
55
+ }
56
+ /**
57
+ * Creates a new {@link IInstanceBuilder} for configuring an AWS EC2 instance.
58
+ *
59
+ * This is the entry point for defining an EC2 instance component. The
60
+ * returned builder exposes every {@link InstanceBuilderProps} property as a
61
+ * fluent setter/getter, plus {@link IInstanceBuilder.vpc | .vpc()} for
62
+ * cross-component VPC wiring with Ref support. It implements
63
+ * {@link Lifecycle} for use with {@link compose}.
64
+ *
65
+ * @returns A fluent builder for an AWS EC2 instance.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const server = createInstanceBuilder()
70
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
71
+ * .instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
72
+ * .machineImage(MachineImage.latestAmazonLinux2023());
73
+ *
74
+ * // Use standalone:
75
+ * const result = server.build(stack, "MyInstance");
76
+ *
77
+ * // Or compose into a system:
78
+ * const system = compose(
79
+ * { network: createVpcBuilder(), server },
80
+ * { network: [], server: ["network"] },
81
+ * );
82
+ * ```
83
+ */
84
+ export function createInstanceBuilder() {
85
+ return Builder(InstanceBuilder);
86
+ }
87
+ //# sourceMappingURL=instance-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-builder.js","sourceRoot":"","sources":["../src/instance-builder.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,GAKT,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,OAAO,EAGP,OAAO,GAER,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAqI3D,MAAM,eAAe;IACnB,KAAK,GAAkC,EAAE,CAAC;IACjC,aAAa,GAAuC,EAAE,CAAC;IAChE,IAAI,CAAoB;IAExB;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAqB;QACvB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACH,QAAQ,CACN,GAAW,EACX,SAAwF;QAExF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,sBAAsB,CAAW,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAiB,EAAE,EAAU,EAAE,OAAgC;QACnE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,oBAAoB,EAAE,6DAA6D,CACpF,CAAC;QACJ,CAAC;QAED,MAAM,EACJ,iBAAiB,EAAE,WAAW,EAC9B,IAAI,EACJ,OAAO,EACP,aAAa,EACb,GAAG,aAAa,EACjB,GAAG,IAAI,CAAC,KAAK,CAAC;QAEf,MAAM,WAAW,GAAG;YAClB,GAAG,iBAAiB;YACpB,GAAG,aAAa;YAChB,GAAG,EAAE,WAAW;YAChB,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC;QAEnB,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,oBAAoB,CACjC,KAAK,EACL,EAAE,EACF,QAAQ,EACR,WAAW,EACX,WAAW,EACX,IAAI,CAAC,aAAa,CACnB,CAAC;QAEF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC9B,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,CAAwC,eAAe,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type InstanceProps } from "aws-cdk-lib/aws-ec2";
2
+ /**
3
+ * Secure, AWS-recommended defaults applied to every EC2 instance built with
4
+ * {@link createInstanceBuilder}. Each property can be individually overridden
5
+ * via the builder's fluent API.
6
+ *
7
+ * Three required properties intentionally have no default — they are
8
+ * application-specific and must be supplied explicitly:
9
+ * - `vpc` (via the builder's `.vpc()` method)
10
+ * - `instanceType`
11
+ * - `machineImage`
12
+ */
13
+ export declare const INSTANCE_DEFAULTS: Partial<InstanceProps>;
14
+ //# sourceMappingURL=instance-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-defaults.d.ts","sourceRoot":"","sources":["../src/instance-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEjG;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,aAAa,CAiDpD,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { BlockDeviceVolume, EbsDeviceVolumeType } from "aws-cdk-lib/aws-ec2";
2
+ /**
3
+ * Secure, AWS-recommended defaults applied to every EC2 instance built with
4
+ * {@link createInstanceBuilder}. Each property can be individually overridden
5
+ * via the builder's fluent API.
6
+ *
7
+ * Three required properties intentionally have no default — they are
8
+ * application-specific and must be supplied explicitly:
9
+ * - `vpc` (via the builder's `.vpc()` method)
10
+ * - `instanceType`
11
+ * - `machineImage`
12
+ */
13
+ export const INSTANCE_DEFAULTS = {
14
+ /**
15
+ * Require IMDSv2. IMDSv1 is vulnerable to SSRF-based credential exfiltration;
16
+ * IMDSv2 requires a session token and blocks the common attack pattern.
17
+ * @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_detect_investigate_events_app_service_logging.html
18
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
19
+ */
20
+ requireImdsv2: true,
21
+ /**
22
+ * Enable detailed (1-minute) CloudWatch metrics. Without this, instance
23
+ * metrics are emitted at 5-minute granularity, which makes short-window
24
+ * alarm evaluation unreliable.
25
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html
26
+ */
27
+ detailedMonitoring: true,
28
+ /**
29
+ * Attach the AmazonSSMManagedInstanceCore managed policy so Session Manager
30
+ * can be used in place of SSH. Removes the need for key pairs, bastion
31
+ * hosts, or inbound SSH access.
32
+ * @see https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html
33
+ */
34
+ ssmSessionPermissions: true,
35
+ /**
36
+ * EBS-optimized networking — dedicated bandwidth between the instance and
37
+ * its EBS volumes. Free and on-by-default for current-generation instance
38
+ * types; set explicitly for consistency.
39
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html
40
+ */
41
+ ebsOptimized: true,
42
+ /**
43
+ * Encrypt the root EBS volume at rest using the account's default EBS KMS
44
+ * key. GP3 is the current-generation general-purpose volume type — cheaper
45
+ * and faster than GP2 at equivalent sizes. Users override this to change
46
+ * volume size, IOPS, throughput, or to add additional block devices.
47
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html
48
+ */
49
+ blockDevices: [
50
+ {
51
+ deviceName: "/dev/xvda",
52
+ volume: BlockDeviceVolume.ebs(8, {
53
+ encrypted: true,
54
+ volumeType: EbsDeviceVolumeType.GP3,
55
+ }),
56
+ },
57
+ ],
58
+ };
59
+ //# sourceMappingURL=instance-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-defaults.js","sourceRoot":"","sources":["../src/instance-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAsB,MAAM,qBAAqB,CAAC;AAEjG;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD;;;;;OAKG;IACH,aAAa,EAAE,IAAI;IAEnB;;;;;OAKG;IACH,kBAAkB,EAAE,IAAI;IAExB;;;;;OAKG;IACH,qBAAqB,EAAE,IAAI;IAE3B;;;;;OAKG;IACH,YAAY,EAAE,IAAI;IAElB;;;;;;OAMG;IACH,YAAY,EAAE;QACZ;YACE,UAAU,EAAE,WAAW;YACvB,MAAM,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE;gBAC/B,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,mBAAmB,CAAC,GAAG;aACpC,CAAC;SACH;KACF;CACF,CAAC"}
@@ -0,0 +1,109 @@
1
+ import { FlowLogDestination, Vpc, type VpcProps } from "aws-cdk-lib/aws-ec2";
2
+ import { type LogGroup } from "aws-cdk-lib/aws-logs";
3
+ import { type IConstruct } from "constructs";
4
+ import { type IBuilder, type Lifecycle } from "@composurecdk/core";
5
+ import { type ILogGroupBuilder } from "@composurecdk/logs";
6
+ /**
7
+ * Configures how VPC flow logs are handled. Pass `false` to disable flow
8
+ * logs; pass an object to wire a destination or customize the auto-created
9
+ * LogGroup sub-builder.
10
+ *
11
+ * `configure` cannot be combined with `destination` — a user-managed
12
+ * destination is not built by this builder.
13
+ *
14
+ * For multiple flow logs against the same VPC, omit this config and create
15
+ * additional `FlowLog` constructs directly against the returned `vpc`.
16
+ *
17
+ * @see https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html
18
+ */
19
+ export type FlowLogsConfig = false | {
20
+ /** A user-managed flow log destination. Cannot be combined with `configure`. */
21
+ destination?: FlowLogDestination;
22
+ /**
23
+ * Customize the auto-created LogGroup sub-builder. Receives a builder
24
+ * pre-seeded with the well-architected log retention/removal defaults
25
+ * from {@link createLogGroupBuilder}.
26
+ */
27
+ configure?: (b: ILogGroupBuilder) => ILogGroupBuilder;
28
+ };
29
+ /**
30
+ * Configuration properties for the VPC builder.
31
+ *
32
+ * Hides the CDK `flowLogs` map field in favor of {@link flowLogs} — a
33
+ * discriminated config that supports an `false` opt-out, a user-managed
34
+ * destination, or a customizable auto-managed LogGroup.
35
+ */
36
+ export interface VpcBuilderProps extends Omit<VpcProps, "flowLogs"> {
37
+ /** See {@link FlowLogsConfig}. Defaults to an auto-managed LogGroup-backed flow log. */
38
+ flowLogs?: FlowLogsConfig;
39
+ }
40
+ /**
41
+ * The build output of a {@link IVpcBuilder}. Contains the CDK constructs
42
+ * created during {@link Lifecycle.build}, keyed by role.
43
+ */
44
+ export interface VpcBuilderResult {
45
+ vpc: Vpc;
46
+ /**
47
+ * The CloudWatch LogGroup created for the auto-managed flow log, or
48
+ * `undefined` when the user supplied their own `destination` or
49
+ * disabled flow logs entirely.
50
+ *
51
+ * @see https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html
52
+ */
53
+ flowLogsLogGroup?: LogGroup;
54
+ }
55
+ /**
56
+ * A fluent builder for configuring and creating an AWS VPC.
57
+ *
58
+ * Each configuration property from the CDK {@link VpcProps} is exposed as an
59
+ * overloaded method: call with a value to set it (returns the builder for
60
+ * chaining), or call with no arguments to read the current value.
61
+ *
62
+ * The builder implements {@link Lifecycle}, so it can be used directly as a
63
+ * component in a {@link compose | composed system}. When built, it creates
64
+ * a VPC with {@link VPC_DEFAULTS | well-architected defaults} and returns a
65
+ * {@link VpcBuilderResult}.
66
+ *
67
+ * By default the builder auto-creates a CloudWatch-Logs-backed flow log
68
+ * using a managed {@link LogGroup} so every VPC gets baseline network audit
69
+ * logging. Customize via {@link FlowLogsConfig} or disable with
70
+ * `flowLogs(false)`.
71
+ *
72
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const network = createVpcBuilder().maxAzs(3).natGateways(3);
77
+ * ```
78
+ */
79
+ export type IVpcBuilder = IBuilder<VpcBuilderProps, VpcBuilder>;
80
+ declare class VpcBuilder implements Lifecycle<VpcBuilderResult> {
81
+ props: Partial<VpcBuilderProps>;
82
+ build(scope: IConstruct, id: string): VpcBuilderResult;
83
+ }
84
+ /**
85
+ * Creates a new {@link IVpcBuilder} for configuring an AWS VPC.
86
+ *
87
+ * This is the entry point for defining a VPC component. The returned builder
88
+ * exposes every {@link VpcBuilderProps} property as a fluent setter/getter
89
+ * and implements {@link Lifecycle} for use with {@link compose}.
90
+ *
91
+ * @returns A fluent builder for an AWS VPC.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const network = createVpcBuilder().maxAzs(3).natGateways(3);
96
+ *
97
+ * // Use standalone:
98
+ * const result = network.build(stack, "Network");
99
+ *
100
+ * // Or compose into a system:
101
+ * const system = compose(
102
+ * { network, server: createInstanceBuilder() },
103
+ * { network: [], server: ["network"] },
104
+ * );
105
+ * ```
106
+ */
107
+ export declare function createVpcBuilder(): IVpcBuilder;
108
+ export {};
109
+ //# sourceMappingURL=vpc-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpc-builder.d.ts","sourceRoot":"","sources":["../src/vpc-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAW,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGlF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GACtB,KAAK,GACL;IACE,gFAAgF;IAChF,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;CACvD,CAAC;AAEN;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC;IACjE,wFAAwF;IACxF,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,GAAG,CAAC;IAET;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,QAAQ,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAIhE,cAAM,UAAW,YAAW,SAAS,CAAC,gBAAgB,CAAC;IACrD,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,CAAM;IAErC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,gBAAgB;CAgBvD;AA2CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C"}
@@ -0,0 +1,79 @@
1
+ import { FlowLogDestination, Vpc } from "aws-cdk-lib/aws-ec2";
2
+ import { Builder } from "@composurecdk/core";
3
+ import { createLogGroupBuilder } from "@composurecdk/logs";
4
+ import { VPC_DEFAULTS } from "./vpc-defaults.js";
5
+ const DEFAULT_FLOW_LOG_KEY = "DefaultFlowLog";
6
+ class VpcBuilder {
7
+ props = {};
8
+ build(scope, id) {
9
+ const { flowLogs: flowLogsConfig, ...vpcProps } = this.props;
10
+ const { flowLogsLogGroup, flowLogProps } = resolveFlowLogs(scope, id, flowLogsConfig);
11
+ const mergedProps = {
12
+ ...VPC_DEFAULTS,
13
+ ...flowLogProps,
14
+ ...vpcProps,
15
+ };
16
+ return {
17
+ vpc: new Vpc(scope, id, mergedProps),
18
+ flowLogsLogGroup,
19
+ };
20
+ }
21
+ }
22
+ function resolveFlowLogs(scope, id, cfg) {
23
+ if (cfg === false) {
24
+ return { flowLogProps: {} };
25
+ }
26
+ if (cfg?.destination !== undefined) {
27
+ if (cfg.configure !== undefined) {
28
+ throw new Error("flowLogs: 'configure' cannot be combined with 'destination' — " +
29
+ "the destination is user-managed and not built by this builder.");
30
+ }
31
+ return {
32
+ flowLogProps: {
33
+ flowLogs: { [DEFAULT_FLOW_LOG_KEY]: { destination: cfg.destination } },
34
+ },
35
+ };
36
+ }
37
+ let subBuilder = createLogGroupBuilder();
38
+ if (cfg?.configure) {
39
+ subBuilder = cfg.configure(subBuilder);
40
+ }
41
+ const flowLogsLogGroup = subBuilder.build(scope, `${id}FlowLogsLogGroup`).logGroup;
42
+ return {
43
+ flowLogsLogGroup,
44
+ flowLogProps: {
45
+ flowLogs: {
46
+ [DEFAULT_FLOW_LOG_KEY]: {
47
+ destination: FlowLogDestination.toCloudWatchLogs(flowLogsLogGroup),
48
+ },
49
+ },
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * Creates a new {@link IVpcBuilder} for configuring an AWS VPC.
55
+ *
56
+ * This is the entry point for defining a VPC component. The returned builder
57
+ * exposes every {@link VpcBuilderProps} property as a fluent setter/getter
58
+ * and implements {@link Lifecycle} for use with {@link compose}.
59
+ *
60
+ * @returns A fluent builder for an AWS VPC.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const network = createVpcBuilder().maxAzs(3).natGateways(3);
65
+ *
66
+ * // Use standalone:
67
+ * const result = network.build(stack, "Network");
68
+ *
69
+ * // Or compose into a system:
70
+ * const system = compose(
71
+ * { network, server: createInstanceBuilder() },
72
+ * { network: [], server: ["network"] },
73
+ * );
74
+ * ```
75
+ */
76
+ export function createVpcBuilder() {
77
+ return Builder(VpcBuilder);
78
+ }
79
+ //# sourceMappingURL=vpc-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpc-builder.js","sourceRoot":"","sources":["../src/vpc-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAiB,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EAAE,OAAO,EAAiC,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAyB,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAmFjD,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAE9C,MAAM,UAAU;IACd,KAAK,GAA6B,EAAE,CAAC;IAErC,KAAK,CAAC,KAAiB,EAAE,EAAU;QACjC,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAE7D,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,GAAG,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;QAEtF,MAAM,WAAW,GAAG;YAClB,GAAG,YAAY;YACf,GAAG,YAAY;YACf,GAAG,QAAQ;SACZ,CAAC;QAEF,OAAO;YACL,GAAG,EAAE,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,WAAW,CAAC;YACpC,gBAAgB;SACjB,CAAC;IACJ,CAAC;CACF;AAED,SAAS,eAAe,CACtB,KAAiB,EACjB,EAAU,EACV,GAA+B;IAE/B,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAC9B,CAAC;IAED,IAAI,GAAG,EAAE,WAAW,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,gEAAgE;gBAC9D,gEAAgE,CACnE,CAAC;QACJ,CAAC;QACD,OAAO;YACL,YAAY,EAAE;gBACZ,QAAQ,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE;aACvE;SACF,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,GAAG,qBAAqB,EAAE,CAAC;IACzC,IAAI,GAAG,EAAE,SAAS,EAAE,CAAC;QACnB,UAAU,GAAG,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,gBAAgB,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAAC;IAEnF,OAAO;QACL,gBAAgB;QAChB,YAAY,EAAE;YACZ,QAAQ,EAAE;gBACR,CAAC,oBAAoB,CAAC,EAAE;oBACtB,WAAW,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,gBAAgB,CAAC;iBACnE;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAA8B,UAAU,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { VpcProps } from "aws-cdk-lib/aws-ec2";
2
+ /**
3
+ * Secure, cost-conscious defaults applied to every VPC built with
4
+ * {@link createVpcBuilder}. Each property can be individually overridden
5
+ * via the builder's fluent API.
6
+ *
7
+ * Subnet layout uses CDK defaults (one public + one private-with-egress
8
+ * subnet per AZ) — override `subnetConfiguration` for custom topologies.
9
+ *
10
+ * Flow logs are created separately by the builder (not via this defaults
11
+ * object) so the destination log group can be auto-managed with
12
+ * well-architected retention/removal policies.
13
+ */
14
+ export declare const VPC_DEFAULTS: Partial<VpcProps>;
15
+ //# sourceMappingURL=vpc-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpc-defaults.d.ts","sourceRoot":"","sources":["../src/vpc-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,CAAC,QAAQ,CA6C1C,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Secure, cost-conscious defaults applied to every VPC built with
3
+ * {@link createVpcBuilder}. Each property can be individually overridden
4
+ * via the builder's fluent API.
5
+ *
6
+ * Subnet layout uses CDK defaults (one public + one private-with-egress
7
+ * subnet per AZ) — override `subnetConfiguration` for custom topologies.
8
+ *
9
+ * Flow logs are created separately by the builder (not via this defaults
10
+ * object) so the destination log group can be auto-managed with
11
+ * well-architected retention/removal policies.
12
+ */
13
+ export const VPC_DEFAULTS = {
14
+ /**
15
+ * Two availability zones strike a balance between high availability
16
+ * and cost. Override to 3+ AZs for production workloads that need
17
+ * stricter HA guarantees.
18
+ * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
19
+ */
20
+ maxAzs: 2,
21
+ /**
22
+ * Single NAT gateway is a cost-conscious default. Production HA
23
+ * workloads should override this to match `maxAzs` so a single-AZ
24
+ * NAT failure does not partition private-subnet egress.
25
+ * @see https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html
26
+ */
27
+ natGateways: 1,
28
+ /**
29
+ * Required for internal DNS resolution for most AWS managed services
30
+ * (ALB, RDS, VPC endpoints). Default-on in AWS but set explicitly for
31
+ * safety across CDK feature-flag configurations.
32
+ * @see https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html
33
+ */
34
+ enableDnsSupport: true,
35
+ /**
36
+ * Required alongside DNS support for instances to receive public DNS
37
+ * hostnames. Needed for most hostname-based TLS and service discovery
38
+ * scenarios.
39
+ * @see https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html
40
+ */
41
+ enableDnsHostnames: true,
42
+ /**
43
+ * Strip all rules from the default security group. This prevents
44
+ * accidentally using the default SG (which allows all intra-SG
45
+ * traffic and no ingress) and forces explicit SG design — a
46
+ * foundational well-architected security practice.
47
+ *
48
+ * Also enabled by the `@aws-cdk/aws-ec2:restrictDefaultSecurityGroup`
49
+ * feature flag; we set it explicitly so the guarantee holds regardless
50
+ * of CDK context configuration.
51
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html#restrictdefaultsecuritygroup
52
+ */
53
+ restrictDefaultSecurityGroup: true,
54
+ };
55
+ //# sourceMappingURL=vpc-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpc-defaults.js","sourceRoot":"","sources":["../src/vpc-defaults.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C;;;;;OAKG;IACH,MAAM,EAAE,CAAC;IAET;;;;;OAKG;IACH,WAAW,EAAE,CAAC;IAEd;;;;;OAKG;IACH,gBAAgB,EAAE,IAAI;IAEtB;;;;;OAKG;IACH,kBAAkB,EAAE,IAAI;IAExB;;;;;;;;;;OAUG;IACH,4BAA4B,EAAE,IAAI;CACnC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@composurecdk/ec2",
3
+ "version": "0.5.0",
4
+ "description": "Composable EC2 instance and VPC builders with well-architected defaults",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/laazyj/composureCDK",
8
+ "directory": "packages/ec2"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "scripts": {
24
+ "clean": "rm -rf dist",
25
+ "build": "tsc -p tsconfig.build.json",
26
+ "typecheck": "tsc --noEmit",
27
+ "test": "vitest run --passWithNoTests",
28
+ "test:watch": "vitest"
29
+ },
30
+ "keywords": [],
31
+ "author": "Jason Duffett (https://github.com/laazyj)",
32
+ "license": "MIT",
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "type": "module",
37
+ "peerDependencies": {
38
+ "@composurecdk/cloudwatch": "^0.5.0",
39
+ "@composurecdk/core": "^0.5.0",
40
+ "@composurecdk/logs": "^0.5.0",
41
+ "aws-cdk-lib": "^2.0.0",
42
+ "constructs": "^10.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^25.5.0",
46
+ "aws-cdk-lib": "^2.245.0",
47
+ "constructs": "^10.6.0",
48
+ "typescript": "^6.0.2",
49
+ "vitest": "^4.1.2"
50
+ }
51
+ }