@composurecdk/ec2 0.8.0 → 0.8.2

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 CHANGED
@@ -220,6 +220,74 @@ createVpcBuilder().flowLogs(false);
220
220
 
221
221
  For multiple flow logs against the same VPC, omit this config and create additional `FlowLog` constructs directly against the returned `vpc`.
222
222
 
223
+ ## Security Group Builder
224
+
225
+ ```ts
226
+ import { createSecurityGroupBuilder } from "@composurecdk/ec2";
227
+ import { Peer, Port } from "aws-cdk-lib/aws-ec2";
228
+
229
+ const web = createSecurityGroupBuilder()
230
+ .vpc(vpc)
231
+ .description("Public web tier")
232
+ .addIngressRule(Peer.anyIpv4(), Port.tcp(443), "Public HTTPS")
233
+ .addEgressRule(Peer.anyIpv4(), Port.tcp(443), "HTTPS to origin")
234
+ .build(stack, "WebSg");
235
+ ```
236
+
237
+ Every [SecurityGroupProps](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SecurityGroupProps.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>(...)`.
238
+
239
+ Ingress and egress rules are accumulated via `addIngressRule`, `addEgressRule`, and `addSelfIngress` (for the intra-SG "allow within the cluster" pattern). Each peer is a `Resolvable<IPeer>`, so it can be a concrete `IPeer` (a CIDR via `Peer.ipv4(...)`, another `ISecurityGroup`, a prefix list, …) or a `Ref` to a sibling component's output.
240
+
241
+ ### Security Group Defaults
242
+
243
+ | Property | Default | Rationale |
244
+ | ------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
245
+ | `allowAllOutbound` | `false` | Closes the implicit `0.0.0.0/0` egress rule CDK ships by default. Every outbound flow becomes an explicit `addEgressRule` — the least-privilege default. |
246
+
247
+ Two properties intentionally have no default — they are application-specific and must be supplied explicitly:
248
+
249
+ - `vpc` (via the `.vpc()` method)
250
+ - `description` (a short, human-readable summary of the SG's purpose; whitespace-only values are rejected)
251
+
252
+ The defaults are exported as `SECURITY_GROUP_DEFAULTS` for visibility and testing:
253
+
254
+ ```ts
255
+ import { SECURITY_GROUP_DEFAULTS } from "@composurecdk/ec2";
256
+ ```
257
+
258
+ ### Wiring two SGs via `ref`
259
+
260
+ The canonical cross-component pattern — a bastion SG and a database SG that talks to it — declares the dependency in `compose()` and resolves the peer at build time:
261
+
262
+ ```ts
263
+ import { compose, ref } from "@composurecdk/core";
264
+ import { createSecurityGroupBuilder, createVpcBuilder } from "@composurecdk/ec2";
265
+ import type { SecurityGroupBuilderResult, VpcBuilderResult } from "@composurecdk/ec2";
266
+ import { Port } from "aws-cdk-lib/aws-ec2";
267
+
268
+ compose(
269
+ {
270
+ network: createVpcBuilder(),
271
+ bastion: createSecurityGroupBuilder()
272
+ .vpc(ref<VpcBuilderResult>("network").get("vpc"))
273
+ .description("Bastion host"),
274
+ database: createSecurityGroupBuilder()
275
+ .vpc(ref<VpcBuilderResult>("network").get("vpc"))
276
+ .description("Database")
277
+ .addIngressRule(
278
+ ref<SecurityGroupBuilderResult>("bastion").get("securityGroup"),
279
+ Port.tcp(5432),
280
+ "Bastion to Postgres",
281
+ ),
282
+ },
283
+ { network: [], bastion: ["network"], database: ["network", "bastion"] },
284
+ ).build(stack, "App");
285
+ ```
286
+
287
+ ### Recommended Alarms
288
+
289
+ The Security Group builder does **not** create CloudWatch alarms. Security groups do not emit CloudWatch metrics — the [AWS recommended-alarms reference](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html) has no SG entry. Operational visibility for SGs comes from adjacent signals (VPC Flow Logs, GuardDuty findings, CloudTrail `AuthorizeSecurityGroupIngress`/`Egress` events), none of which belong on the builder result.
290
+
223
291
  ## Volume Builder
224
292
 
225
293
  ```ts
@@ -11,4 +11,6 @@ export { type VolumeAlarmConfig } from "./volume-alarm-config.js";
11
11
  export { VOLUME_ALARM_DEFAULTS } from "./volume-alarm-defaults.js";
12
12
  export { createVpcBuilder, type FlowLogsConfig, type IVpcBuilder, type VpcBuilderProps, type VpcBuilderResult, } from "./vpc-builder.js";
13
13
  export { VPC_DEFAULTS } from "./vpc-defaults.js";
14
+ export { createSecurityGroupBuilder, type ISecurityGroupBuilder, type SecurityGroupBuilderProps, type SecurityGroupBuilderResult, } from "./security-group-builder.js";
15
+ export { SECURITY_GROUP_DEFAULTS } from "./security-group-defaults.js";
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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;AACvE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,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"}
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;AACvE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,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;AAEjD,OAAO,EACL,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VPC_DEFAULTS = exports.createVpcBuilder = exports.VOLUME_ALARM_DEFAULTS = exports.VOLUME_DEFAULTS = exports.createVolumeBuilder = exports.VOLUME_ATTACHMENT_ALARM_DEFAULTS = exports.INSTANCE_ALARM_DEFAULTS = exports.INSTANCE_DEFAULTS = exports.createInstanceBuilder = void 0;
3
+ exports.SECURITY_GROUP_DEFAULTS = exports.createSecurityGroupBuilder = exports.VPC_DEFAULTS = exports.createVpcBuilder = exports.VOLUME_ALARM_DEFAULTS = exports.VOLUME_DEFAULTS = exports.createVolumeBuilder = exports.VOLUME_ATTACHMENT_ALARM_DEFAULTS = exports.INSTANCE_ALARM_DEFAULTS = exports.INSTANCE_DEFAULTS = exports.createInstanceBuilder = void 0;
4
4
  var instance_builder_js_1 = require("./instance-builder.js");
5
5
  Object.defineProperty(exports, "createInstanceBuilder", { enumerable: true, get: function () { return instance_builder_js_1.createInstanceBuilder; } });
6
6
  var instance_defaults_js_1 = require("./instance-defaults.js");
@@ -19,4 +19,8 @@ var vpc_builder_js_1 = require("./vpc-builder.js");
19
19
  Object.defineProperty(exports, "createVpcBuilder", { enumerable: true, get: function () { return vpc_builder_js_1.createVpcBuilder; } });
20
20
  var vpc_defaults_js_1 = require("./vpc-defaults.js");
21
21
  Object.defineProperty(exports, "VPC_DEFAULTS", { enumerable: true, get: function () { return vpc_defaults_js_1.VPC_DEFAULTS; } });
22
+ var security_group_builder_js_1 = require("./security-group-builder.js");
23
+ Object.defineProperty(exports, "createSecurityGroupBuilder", { enumerable: true, get: function () { return security_group_builder_js_1.createSecurityGroupBuilder; } });
24
+ var security_group_defaults_js_1 = require("./security-group-defaults.js");
25
+ Object.defineProperty(exports, "SECURITY_GROUP_DEFAULTS", { enumerable: true, get: function () { return security_group_defaults_js_1.SECURITY_GROUP_DEFAULTS; } });
22
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAK+B;AAJ7B,4HAAA,qBAAqB,OAAA;AAKvB,+DAA2D;AAAlD,yHAAA,iBAAiB,OAAA;AAE1B,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAGhC,mGAA4F;AAAnF,0JAAA,gCAAgC,OAAA;AAEzC,yDAK6B;AAJ3B,wHAAA,mBAAmB,OAAA;AAKrB,2DAAuD;AAA9C,qHAAA,eAAe,OAAA;AAExB,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA;AAE9B,mDAM0B;AALxB,kHAAA,gBAAgB,OAAA;AAMlB,qDAAiD;AAAxC,+GAAA,YAAY,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAK+B;AAJ7B,4HAAA,qBAAqB,OAAA;AAKvB,+DAA2D;AAAlD,yHAAA,iBAAiB,OAAA;AAE1B,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAGhC,mGAA4F;AAAnF,0JAAA,gCAAgC,OAAA;AAEzC,yDAK6B;AAJ3B,wHAAA,mBAAmB,OAAA;AAKrB,2DAAuD;AAA9C,qHAAA,eAAe,OAAA;AAExB,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA;AAE9B,mDAM0B;AALxB,kHAAA,gBAAgB,OAAA;AAMlB,qDAAiD;AAAxC,+GAAA,YAAY,OAAA;AAErB,yEAKqC;AAJnC,uIAAA,0BAA0B,OAAA;AAK5B,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA"}
@@ -0,0 +1,148 @@
1
+ import { type IPeer, type IVpc, type Port, SecurityGroup, type SecurityGroupProps } from "aws-cdk-lib/aws-ec2";
2
+ import { type IConstruct } from "constructs";
3
+ import { COPY_STATE, type Lifecycle, type Resolvable } from "@composurecdk/core";
4
+ import { type ITaggedBuilder } from "@composurecdk/cloudformation";
5
+ /**
6
+ * Configuration properties for the security group builder.
7
+ *
8
+ * Extends the CDK {@link SecurityGroupProps} but lifts `vpc` off the props
9
+ * object — it is supplied via the dedicated
10
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} method so it can accept a
11
+ * {@link Resolvable} for cross-component wiring (e.g. a sibling
12
+ * `VpcBuilder`).
13
+ *
14
+ * Ingress and egress rules are added imperatively via
15
+ * {@link ISecurityGroupBuilder.addIngressRule | .addIngressRule()},
16
+ * {@link ISecurityGroupBuilder.addEgressRule | .addEgressRule()}, and
17
+ * {@link ISecurityGroupBuilder.addSelfIngress | .addSelfIngress()} so each
18
+ * peer can also be a {@link Resolvable}.
19
+ */
20
+ export type SecurityGroupBuilderProps = Omit<SecurityGroupProps, "vpc">;
21
+ /**
22
+ * The build output of an {@link ISecurityGroupBuilder}. Contains the CDK
23
+ * constructs created during {@link Lifecycle.build}, keyed by role.
24
+ *
25
+ * The `securityGroup` is itself an `IConnectable` and `IPeer`, so consumers
26
+ * compose against it directly — there is no separate `connections` field on
27
+ * the result.
28
+ *
29
+ * The builder creates no CloudWatch alarms. Security groups do not emit
30
+ * CloudWatch metrics, so the
31
+ * [recommended-alarms reference](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html)
32
+ * has no SG entry. Operational visibility comes from adjacent signals —
33
+ * VPC Flow Logs, GuardDuty findings, CloudTrail authorize-events.
34
+ */
35
+ export interface SecurityGroupBuilderResult {
36
+ securityGroup: SecurityGroup;
37
+ }
38
+ /**
39
+ * A fluent builder for configuring and creating an AWS EC2 security group.
40
+ *
41
+ * Each configuration property from the CDK {@link SecurityGroupProps} (other
42
+ * than `vpc`) is exposed as an overloaded method: call with a value to set
43
+ * it, or with no arguments to read it. The `vpc` is set via the dedicated
44
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} method that accepts a
45
+ * {@link Resolvable} for cross-component wiring with sibling builders.
46
+ *
47
+ * Ingress and egress rules are accumulated via
48
+ * {@link ISecurityGroupBuilder.addIngressRule | .addIngressRule()},
49
+ * {@link ISecurityGroupBuilder.addEgressRule | .addEgressRule()}, and
50
+ * {@link ISecurityGroupBuilder.addSelfIngress | .addSelfIngress()} and
51
+ * applied when {@link Lifecycle.build | build()} runs. Each peer is a
52
+ * {@link Resolvable} so it can be a concrete `IPeer` (including another
53
+ * `ISecurityGroup`) or a {@link ref | Ref} to a sibling component's output.
54
+ *
55
+ * The builder implements {@link Lifecycle}, so it can be used directly as a
56
+ * component in a {@link compose | composed system}.
57
+ *
58
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SecurityGroup.html
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * compose(
63
+ * {
64
+ * network: createVpcBuilder(),
65
+ * bastion: createSecurityGroupBuilder()
66
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
67
+ * .description("Bastion host"),
68
+ * database: createSecurityGroupBuilder()
69
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
70
+ * .description("Database")
71
+ * .addIngressRule(
72
+ * ref<SecurityGroupBuilderResult>("bastion").get("securityGroup"),
73
+ * Port.tcp(5432),
74
+ * "Bastion to Postgres",
75
+ * ),
76
+ * },
77
+ * { network: [], bastion: ["network"], database: ["network", "bastion"] },
78
+ * );
79
+ * ```
80
+ */
81
+ export type ISecurityGroupBuilder = ITaggedBuilder<SecurityGroupBuilderProps, SecurityGroupBuilder>;
82
+ declare class SecurityGroupBuilder implements Lifecycle<SecurityGroupBuilderResult> {
83
+ #private;
84
+ props: Partial<SecurityGroupBuilderProps>;
85
+ /**
86
+ * Sets the VPC the security group is created in.
87
+ *
88
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
89
+ * at build time — e.g. a sibling {@link IVpcBuilder} in the same
90
+ * composed system.
91
+ *
92
+ * @param vpc - The VPC or a Ref to one.
93
+ * @returns This builder for chaining.
94
+ */
95
+ vpc(vpc: Resolvable<IVpc>): this;
96
+ /**
97
+ * Adds an ingress rule. The peer accepts any {@link IPeer} — a concrete
98
+ * `Peer.ipv4(...)`, another `ISecurityGroup`, a prefix list — or a
99
+ * {@link Ref} that resolves to one.
100
+ *
101
+ * @param peer - The source of the allowed traffic.
102
+ * @param port - The port or port range.
103
+ * @param description - Optional human-readable description of the rule.
104
+ * @returns This builder for chaining.
105
+ */
106
+ addIngressRule(peer: Resolvable<IPeer>, port: Port, description?: string): this;
107
+ /**
108
+ * Adds an egress rule. Required when `allowAllOutbound` is `false`
109
+ * (the builder default — see {@link SECURITY_GROUP_DEFAULTS}). The peer
110
+ * accepts any {@link IPeer} or a {@link Ref} that resolves to one.
111
+ *
112
+ * @param peer - The destination of the allowed traffic.
113
+ * @param port - The port or port range.
114
+ * @param description - Optional human-readable description of the rule.
115
+ * @returns This builder for chaining.
116
+ */
117
+ addEgressRule(peer: Resolvable<IPeer>, port: Port, description?: string): this;
118
+ /**
119
+ * Adds an ingress rule whose peer is the security group itself —
120
+ * the canonical "allow intra-SG traffic on port N" pattern. The peer
121
+ * cannot be expressed at configuration time because the security group
122
+ * identity does not exist yet; the builder wires it after the SG is
123
+ * constructed.
124
+ *
125
+ * @param port - The port or port range.
126
+ * @param description - Optional human-readable description of the rule.
127
+ * @returns This builder for chaining.
128
+ */
129
+ addSelfIngress(port: Port, description?: string): this;
130
+ /** @internal — see ADR-0005. */
131
+ [COPY_STATE](target: SecurityGroupBuilder): void;
132
+ build(scope: IConstruct, id: string, context?: Record<string, object>): SecurityGroupBuilderResult;
133
+ }
134
+ /**
135
+ * Creates a new {@link ISecurityGroupBuilder} for configuring an AWS EC2
136
+ * security group.
137
+ *
138
+ * The returned builder exposes every {@link SecurityGroupBuilderProps}
139
+ * property as a fluent setter/getter, plus
140
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} for cross-component VPC wiring
141
+ * and the `addIngressRule` / `addEgressRule` / `addSelfIngress` accumulators.
142
+ * It implements {@link Lifecycle} for use with {@link compose}.
143
+ *
144
+ * @returns A fluent builder for an AWS EC2 security group.
145
+ */
146
+ export declare function createSecurityGroupBuilder(): ISecurityGroupBuilder;
147
+ export {};
148
+ //# sourceMappingURL=security-group-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-builder.d.ts","sourceRoot":"","sources":["../../src/security-group-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,IAAI,EACT,KAAK,IAAI,EACT,aAAa,EACb,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAW,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,8BAA8B,CAAC;AAGlF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;AAExE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,aAAa,CAAC;CAC9B;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC;AAEpG,cAAM,oBAAqB,YAAW,SAAS,CAAC,0BAA0B,CAAC;;IACzE,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAM;IAK/C;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI;IAKhC;;;;;;;;;OASG;IACH,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAU/E;;;;;;;;;OASG;IACH,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9E;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAQtD,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAMhD,KAAK,CACH,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,0BAA0B;CAiD9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,IAAI,qBAAqB,CAElE"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSecurityGroupBuilder = createSecurityGroupBuilder;
4
+ const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
5
+ const core_1 = require("@composurecdk/core");
6
+ const cloudformation_1 = require("@composurecdk/cloudformation");
7
+ const security_group_defaults_js_1 = require("./security-group-defaults.js");
8
+ class SecurityGroupBuilder {
9
+ props = {};
10
+ #peerRules = [];
11
+ #selfIngress = [];
12
+ #vpc;
13
+ /**
14
+ * Sets the VPC the security group is created in.
15
+ *
16
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
17
+ * at build time — e.g. a sibling {@link IVpcBuilder} in the same
18
+ * composed system.
19
+ *
20
+ * @param vpc - The VPC or a Ref to one.
21
+ * @returns This builder for chaining.
22
+ */
23
+ vpc(vpc) {
24
+ this.#vpc = vpc;
25
+ return this;
26
+ }
27
+ /**
28
+ * Adds an ingress rule. The peer accepts any {@link IPeer} — a concrete
29
+ * `Peer.ipv4(...)`, another `ISecurityGroup`, a prefix list — or a
30
+ * {@link Ref} that resolves to one.
31
+ *
32
+ * @param peer - The source of the allowed traffic.
33
+ * @param port - The port or port range.
34
+ * @param description - Optional human-readable description of the rule.
35
+ * @returns This builder for chaining.
36
+ */
37
+ addIngressRule(peer, port, description) {
38
+ this.#peerRules.push({
39
+ direction: "ingress",
40
+ peer,
41
+ port,
42
+ ...(description !== undefined ? { description } : {}),
43
+ });
44
+ return this;
45
+ }
46
+ /**
47
+ * Adds an egress rule. Required when `allowAllOutbound` is `false`
48
+ * (the builder default — see {@link SECURITY_GROUP_DEFAULTS}). The peer
49
+ * accepts any {@link IPeer} or a {@link Ref} that resolves to one.
50
+ *
51
+ * @param peer - The destination of the allowed traffic.
52
+ * @param port - The port or port range.
53
+ * @param description - Optional human-readable description of the rule.
54
+ * @returns This builder for chaining.
55
+ */
56
+ addEgressRule(peer, port, description) {
57
+ this.#peerRules.push({
58
+ direction: "egress",
59
+ peer,
60
+ port,
61
+ ...(description !== undefined ? { description } : {}),
62
+ });
63
+ return this;
64
+ }
65
+ /**
66
+ * Adds an ingress rule whose peer is the security group itself —
67
+ * the canonical "allow intra-SG traffic on port N" pattern. The peer
68
+ * cannot be expressed at configuration time because the security group
69
+ * identity does not exist yet; the builder wires it after the SG is
70
+ * constructed.
71
+ *
72
+ * @param port - The port or port range.
73
+ * @param description - Optional human-readable description of the rule.
74
+ * @returns This builder for chaining.
75
+ */
76
+ addSelfIngress(port, description) {
77
+ this.#selfIngress.push({
78
+ port,
79
+ ...(description !== undefined ? { description } : {}),
80
+ });
81
+ return this;
82
+ }
83
+ /** @internal — see ADR-0005. */
84
+ [core_1.COPY_STATE](target) {
85
+ target.#vpc = this.#vpc;
86
+ target.#peerRules.push(...this.#peerRules);
87
+ target.#selfIngress.push(...this.#selfIngress);
88
+ }
89
+ build(scope, id, context) {
90
+ const resolvedVpc = this.#vpc ? (0, core_1.resolve)(this.#vpc, context) : undefined;
91
+ if (!resolvedVpc) {
92
+ throw new Error(`SecurityGroupBuilder "${id}" requires a VPC. ` +
93
+ "Call .vpc() with an IVpc or a Ref to one.");
94
+ }
95
+ if (this.props.description === undefined || this.props.description.trim() === "") {
96
+ throw new Error(`SecurityGroupBuilder "${id}" requires a description. ` +
97
+ "Call .description() with a short summary of the SG's purpose.");
98
+ }
99
+ // Drop keys whose value is `undefined` so a fluent call like
100
+ // `.allowAllOutbound(undefined)` (common in "optional override" code:
101
+ // `b.allowAllOutbound(cfg?.allowAllOutbound)`) does not clobber the
102
+ // closed-egress default with explicit `undefined`.
103
+ const userProps = {};
104
+ for (const key of Object.keys(this.props)) {
105
+ const value = this.props[key];
106
+ if (value !== undefined) {
107
+ userProps[key] = value;
108
+ }
109
+ }
110
+ const mergedProps = {
111
+ ...security_group_defaults_js_1.SECURITY_GROUP_DEFAULTS,
112
+ ...userProps,
113
+ vpc: resolvedVpc,
114
+ };
115
+ const securityGroup = new aws_ec2_1.SecurityGroup(scope, id, mergedProps);
116
+ for (const rule of this.#peerRules) {
117
+ const peer = (0, core_1.resolve)(rule.peer, context);
118
+ if (rule.direction === "ingress") {
119
+ securityGroup.addIngressRule(peer, rule.port, rule.description);
120
+ }
121
+ else {
122
+ securityGroup.addEgressRule(peer, rule.port, rule.description);
123
+ }
124
+ }
125
+ for (const rule of this.#selfIngress) {
126
+ securityGroup.addIngressRule(securityGroup, rule.port, rule.description);
127
+ }
128
+ return { securityGroup };
129
+ }
130
+ }
131
+ /**
132
+ * Creates a new {@link ISecurityGroupBuilder} for configuring an AWS EC2
133
+ * security group.
134
+ *
135
+ * The returned builder exposes every {@link SecurityGroupBuilderProps}
136
+ * property as a fluent setter/getter, plus
137
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} for cross-component VPC wiring
138
+ * and the `addIngressRule` / `addEgressRule` / `addSelfIngress` accumulators.
139
+ * It implements {@link Lifecycle} for use with {@link compose}.
140
+ *
141
+ * @returns A fluent builder for an AWS EC2 security group.
142
+ */
143
+ function createSecurityGroupBuilder() {
144
+ return (0, cloudformation_1.taggedBuilder)(SecurityGroupBuilder);
145
+ }
146
+ //# sourceMappingURL=security-group-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-builder.js","sourceRoot":"","sources":["../../src/security-group-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { SecurityGroupProps } from "aws-cdk-lib/aws-ec2";
2
+ /**
3
+ * Secure, AWS-recommended defaults applied to every security group built
4
+ * with {@link createSecurityGroupBuilder}. Each property can be individually
5
+ * overridden via the builder's fluent API.
6
+ *
7
+ * Two properties intentionally have no default — they are application-
8
+ * specific and must be supplied explicitly:
9
+ * - `vpc` (via the builder's `.vpc()` method)
10
+ * - `description` (a short, human-readable summary of the SG's purpose)
11
+ */
12
+ export declare const SECURITY_GROUP_DEFAULTS: Partial<SecurityGroupProps>;
13
+ //# sourceMappingURL=security-group-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-defaults.d.ts","sourceRoot":"","sources":["../../src/security-group-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,OAAO,CAAC,kBAAkB,CAY/D,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECURITY_GROUP_DEFAULTS = void 0;
4
+ /**
5
+ * Secure, AWS-recommended defaults applied to every security group built
6
+ * with {@link createSecurityGroupBuilder}. Each property can be individually
7
+ * overridden via the builder's fluent API.
8
+ *
9
+ * Two properties intentionally have no default — they are application-
10
+ * specific and must be supplied explicitly:
11
+ * - `vpc` (via the builder's `.vpc()` method)
12
+ * - `description` (a short, human-readable summary of the SG's purpose)
13
+ */
14
+ exports.SECURITY_GROUP_DEFAULTS = {
15
+ /**
16
+ * Closed-by-default egress. CDK's stock default is `true`, which creates
17
+ * an implicit `0.0.0.0/0` outbound rule on every SG — flagged by
18
+ * compliance scanners and incompatible with the project's least-privilege
19
+ * stance. Closing egress forces every outbound flow to be expressed as
20
+ * an explicit `addEgressRule` (or `.allowAllOutbound(true)` to opt back
21
+ * into the CDK default).
22
+ *
23
+ * @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_network_protection_layered.html
24
+ */
25
+ allowAllOutbound: false,
26
+ };
27
+ //# sourceMappingURL=security-group-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-defaults.js","sourceRoot":"","sources":["../../src/security-group-defaults.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;GASG;AACU,QAAA,uBAAuB,GAAgC;IAClE;;;;;;;;;OASG;IACH,gBAAgB,EAAE,KAAK;CACxB,CAAC"}
@@ -11,4 +11,6 @@ export { type VolumeAlarmConfig } from "./volume-alarm-config.js";
11
11
  export { VOLUME_ALARM_DEFAULTS } from "./volume-alarm-defaults.js";
12
12
  export { createVpcBuilder, type FlowLogsConfig, type IVpcBuilder, type VpcBuilderProps, type VpcBuilderResult, } from "./vpc-builder.js";
13
13
  export { VPC_DEFAULTS } from "./vpc-defaults.js";
14
+ export { createSecurityGroupBuilder, type ISecurityGroupBuilder, type SecurityGroupBuilderProps, type SecurityGroupBuilderResult, } from "./security-group-builder.js";
15
+ export { SECURITY_GROUP_DEFAULTS } from "./security-group-defaults.js";
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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;AACvE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,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"}
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;AACvE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,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;AAEjD,OAAO,EACL,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/esm/index.js CHANGED
@@ -7,4 +7,6 @@ export { VOLUME_DEFAULTS } from "./volume-defaults.js";
7
7
  export { VOLUME_ALARM_DEFAULTS } from "./volume-alarm-defaults.js";
8
8
  export { createVpcBuilder, } from "./vpc-builder.js";
9
9
  export { VPC_DEFAULTS } from "./vpc-defaults.js";
10
+ export { createSecurityGroupBuilder, } from "./security-group-builder.js";
11
+ export { SECURITY_GROUP_DEFAULTS } from "./security-group-defaults.js";
10
12
  //# sourceMappingURL=index.js.map
@@ -1 +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;AAGvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,GAIpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EACL,gBAAgB,GAKjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
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;AAGvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,OAAO,EACL,mBAAmB,GAIpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EACL,gBAAgB,GAKjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EACL,0BAA0B,GAI3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,148 @@
1
+ import { type IPeer, type IVpc, type Port, SecurityGroup, type SecurityGroupProps } from "aws-cdk-lib/aws-ec2";
2
+ import { type IConstruct } from "constructs";
3
+ import { COPY_STATE, type Lifecycle, type Resolvable } from "@composurecdk/core";
4
+ import { type ITaggedBuilder } from "@composurecdk/cloudformation";
5
+ /**
6
+ * Configuration properties for the security group builder.
7
+ *
8
+ * Extends the CDK {@link SecurityGroupProps} but lifts `vpc` off the props
9
+ * object — it is supplied via the dedicated
10
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} method so it can accept a
11
+ * {@link Resolvable} for cross-component wiring (e.g. a sibling
12
+ * `VpcBuilder`).
13
+ *
14
+ * Ingress and egress rules are added imperatively via
15
+ * {@link ISecurityGroupBuilder.addIngressRule | .addIngressRule()},
16
+ * {@link ISecurityGroupBuilder.addEgressRule | .addEgressRule()}, and
17
+ * {@link ISecurityGroupBuilder.addSelfIngress | .addSelfIngress()} so each
18
+ * peer can also be a {@link Resolvable}.
19
+ */
20
+ export type SecurityGroupBuilderProps = Omit<SecurityGroupProps, "vpc">;
21
+ /**
22
+ * The build output of an {@link ISecurityGroupBuilder}. Contains the CDK
23
+ * constructs created during {@link Lifecycle.build}, keyed by role.
24
+ *
25
+ * The `securityGroup` is itself an `IConnectable` and `IPeer`, so consumers
26
+ * compose against it directly — there is no separate `connections` field on
27
+ * the result.
28
+ *
29
+ * The builder creates no CloudWatch alarms. Security groups do not emit
30
+ * CloudWatch metrics, so the
31
+ * [recommended-alarms reference](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html)
32
+ * has no SG entry. Operational visibility comes from adjacent signals —
33
+ * VPC Flow Logs, GuardDuty findings, CloudTrail authorize-events.
34
+ */
35
+ export interface SecurityGroupBuilderResult {
36
+ securityGroup: SecurityGroup;
37
+ }
38
+ /**
39
+ * A fluent builder for configuring and creating an AWS EC2 security group.
40
+ *
41
+ * Each configuration property from the CDK {@link SecurityGroupProps} (other
42
+ * than `vpc`) is exposed as an overloaded method: call with a value to set
43
+ * it, or with no arguments to read it. The `vpc` is set via the dedicated
44
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} method that accepts a
45
+ * {@link Resolvable} for cross-component wiring with sibling builders.
46
+ *
47
+ * Ingress and egress rules are accumulated via
48
+ * {@link ISecurityGroupBuilder.addIngressRule | .addIngressRule()},
49
+ * {@link ISecurityGroupBuilder.addEgressRule | .addEgressRule()}, and
50
+ * {@link ISecurityGroupBuilder.addSelfIngress | .addSelfIngress()} and
51
+ * applied when {@link Lifecycle.build | build()} runs. Each peer is a
52
+ * {@link Resolvable} so it can be a concrete `IPeer` (including another
53
+ * `ISecurityGroup`) or a {@link ref | Ref} to a sibling component's output.
54
+ *
55
+ * The builder implements {@link Lifecycle}, so it can be used directly as a
56
+ * component in a {@link compose | composed system}.
57
+ *
58
+ * @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SecurityGroup.html
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * compose(
63
+ * {
64
+ * network: createVpcBuilder(),
65
+ * bastion: createSecurityGroupBuilder()
66
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
67
+ * .description("Bastion host"),
68
+ * database: createSecurityGroupBuilder()
69
+ * .vpc(ref<VpcBuilderResult>("network").get("vpc"))
70
+ * .description("Database")
71
+ * .addIngressRule(
72
+ * ref<SecurityGroupBuilderResult>("bastion").get("securityGroup"),
73
+ * Port.tcp(5432),
74
+ * "Bastion to Postgres",
75
+ * ),
76
+ * },
77
+ * { network: [], bastion: ["network"], database: ["network", "bastion"] },
78
+ * );
79
+ * ```
80
+ */
81
+ export type ISecurityGroupBuilder = ITaggedBuilder<SecurityGroupBuilderProps, SecurityGroupBuilder>;
82
+ declare class SecurityGroupBuilder implements Lifecycle<SecurityGroupBuilderResult> {
83
+ #private;
84
+ props: Partial<SecurityGroupBuilderProps>;
85
+ /**
86
+ * Sets the VPC the security group is created in.
87
+ *
88
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
89
+ * at build time — e.g. a sibling {@link IVpcBuilder} in the same
90
+ * composed system.
91
+ *
92
+ * @param vpc - The VPC or a Ref to one.
93
+ * @returns This builder for chaining.
94
+ */
95
+ vpc(vpc: Resolvable<IVpc>): this;
96
+ /**
97
+ * Adds an ingress rule. The peer accepts any {@link IPeer} — a concrete
98
+ * `Peer.ipv4(...)`, another `ISecurityGroup`, a prefix list — or a
99
+ * {@link Ref} that resolves to one.
100
+ *
101
+ * @param peer - The source of the allowed traffic.
102
+ * @param port - The port or port range.
103
+ * @param description - Optional human-readable description of the rule.
104
+ * @returns This builder for chaining.
105
+ */
106
+ addIngressRule(peer: Resolvable<IPeer>, port: Port, description?: string): this;
107
+ /**
108
+ * Adds an egress rule. Required when `allowAllOutbound` is `false`
109
+ * (the builder default — see {@link SECURITY_GROUP_DEFAULTS}). The peer
110
+ * accepts any {@link IPeer} or a {@link Ref} that resolves to one.
111
+ *
112
+ * @param peer - The destination of the allowed traffic.
113
+ * @param port - The port or port range.
114
+ * @param description - Optional human-readable description of the rule.
115
+ * @returns This builder for chaining.
116
+ */
117
+ addEgressRule(peer: Resolvable<IPeer>, port: Port, description?: string): this;
118
+ /**
119
+ * Adds an ingress rule whose peer is the security group itself —
120
+ * the canonical "allow intra-SG traffic on port N" pattern. The peer
121
+ * cannot be expressed at configuration time because the security group
122
+ * identity does not exist yet; the builder wires it after the SG is
123
+ * constructed.
124
+ *
125
+ * @param port - The port or port range.
126
+ * @param description - Optional human-readable description of the rule.
127
+ * @returns This builder for chaining.
128
+ */
129
+ addSelfIngress(port: Port, description?: string): this;
130
+ /** @internal — see ADR-0005. */
131
+ [COPY_STATE](target: SecurityGroupBuilder): void;
132
+ build(scope: IConstruct, id: string, context?: Record<string, object>): SecurityGroupBuilderResult;
133
+ }
134
+ /**
135
+ * Creates a new {@link ISecurityGroupBuilder} for configuring an AWS EC2
136
+ * security group.
137
+ *
138
+ * The returned builder exposes every {@link SecurityGroupBuilderProps}
139
+ * property as a fluent setter/getter, plus
140
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} for cross-component VPC wiring
141
+ * and the `addIngressRule` / `addEgressRule` / `addSelfIngress` accumulators.
142
+ * It implements {@link Lifecycle} for use with {@link compose}.
143
+ *
144
+ * @returns A fluent builder for an AWS EC2 security group.
145
+ */
146
+ export declare function createSecurityGroupBuilder(): ISecurityGroupBuilder;
147
+ export {};
148
+ //# sourceMappingURL=security-group-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-builder.d.ts","sourceRoot":"","sources":["../../src/security-group-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,IAAI,EACT,KAAK,IAAI,EACT,aAAa,EACb,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAW,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,8BAA8B,CAAC;AAGlF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;AAExE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,aAAa,CAAC;CAC9B;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC;AAEpG,cAAM,oBAAqB,YAAW,SAAS,CAAC,0BAA0B,CAAC;;IACzE,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAM;IAK/C;;;;;;;;;OASG;IACH,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI;IAKhC;;;;;;;;;OASG;IACH,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAU/E;;;;;;;;;OASG;IACH,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9E;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAQtD,gCAAgC;IAChC,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAMhD,KAAK,CACH,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,0BAA0B;CAiD9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,IAAI,qBAAqB,CAElE"}
@@ -0,0 +1,143 @@
1
+ import { SecurityGroup, } from "aws-cdk-lib/aws-ec2";
2
+ import { COPY_STATE, resolve } from "@composurecdk/core";
3
+ import { taggedBuilder } from "@composurecdk/cloudformation";
4
+ import { SECURITY_GROUP_DEFAULTS } from "./security-group-defaults.js";
5
+ class SecurityGroupBuilder {
6
+ props = {};
7
+ #peerRules = [];
8
+ #selfIngress = [];
9
+ #vpc;
10
+ /**
11
+ * Sets the VPC the security group is created in.
12
+ *
13
+ * Accepts a concrete {@link IVpc} or a {@link Ref} that resolves to one
14
+ * at build time — e.g. a sibling {@link IVpcBuilder} in the same
15
+ * 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 an ingress rule. The peer accepts any {@link IPeer} — a concrete
26
+ * `Peer.ipv4(...)`, another `ISecurityGroup`, a prefix list — or a
27
+ * {@link Ref} that resolves to one.
28
+ *
29
+ * @param peer - The source of the allowed traffic.
30
+ * @param port - The port or port range.
31
+ * @param description - Optional human-readable description of the rule.
32
+ * @returns This builder for chaining.
33
+ */
34
+ addIngressRule(peer, port, description) {
35
+ this.#peerRules.push({
36
+ direction: "ingress",
37
+ peer,
38
+ port,
39
+ ...(description !== undefined ? { description } : {}),
40
+ });
41
+ return this;
42
+ }
43
+ /**
44
+ * Adds an egress rule. Required when `allowAllOutbound` is `false`
45
+ * (the builder default — see {@link SECURITY_GROUP_DEFAULTS}). The peer
46
+ * accepts any {@link IPeer} or a {@link Ref} that resolves to one.
47
+ *
48
+ * @param peer - The destination of the allowed traffic.
49
+ * @param port - The port or port range.
50
+ * @param description - Optional human-readable description of the rule.
51
+ * @returns This builder for chaining.
52
+ */
53
+ addEgressRule(peer, port, description) {
54
+ this.#peerRules.push({
55
+ direction: "egress",
56
+ peer,
57
+ port,
58
+ ...(description !== undefined ? { description } : {}),
59
+ });
60
+ return this;
61
+ }
62
+ /**
63
+ * Adds an ingress rule whose peer is the security group itself —
64
+ * the canonical "allow intra-SG traffic on port N" pattern. The peer
65
+ * cannot be expressed at configuration time because the security group
66
+ * identity does not exist yet; the builder wires it after the SG is
67
+ * constructed.
68
+ *
69
+ * @param port - The port or port range.
70
+ * @param description - Optional human-readable description of the rule.
71
+ * @returns This builder for chaining.
72
+ */
73
+ addSelfIngress(port, description) {
74
+ this.#selfIngress.push({
75
+ port,
76
+ ...(description !== undefined ? { description } : {}),
77
+ });
78
+ return this;
79
+ }
80
+ /** @internal — see ADR-0005. */
81
+ [COPY_STATE](target) {
82
+ target.#vpc = this.#vpc;
83
+ target.#peerRules.push(...this.#peerRules);
84
+ target.#selfIngress.push(...this.#selfIngress);
85
+ }
86
+ build(scope, id, context) {
87
+ const resolvedVpc = this.#vpc ? resolve(this.#vpc, context) : undefined;
88
+ if (!resolvedVpc) {
89
+ throw new Error(`SecurityGroupBuilder "${id}" requires a VPC. ` +
90
+ "Call .vpc() with an IVpc or a Ref to one.");
91
+ }
92
+ if (this.props.description === undefined || this.props.description.trim() === "") {
93
+ throw new Error(`SecurityGroupBuilder "${id}" requires a description. ` +
94
+ "Call .description() with a short summary of the SG's purpose.");
95
+ }
96
+ // Drop keys whose value is `undefined` so a fluent call like
97
+ // `.allowAllOutbound(undefined)` (common in "optional override" code:
98
+ // `b.allowAllOutbound(cfg?.allowAllOutbound)`) does not clobber the
99
+ // closed-egress default with explicit `undefined`.
100
+ const userProps = {};
101
+ for (const key of Object.keys(this.props)) {
102
+ const value = this.props[key];
103
+ if (value !== undefined) {
104
+ userProps[key] = value;
105
+ }
106
+ }
107
+ const mergedProps = {
108
+ ...SECURITY_GROUP_DEFAULTS,
109
+ ...userProps,
110
+ vpc: resolvedVpc,
111
+ };
112
+ const securityGroup = new SecurityGroup(scope, id, mergedProps);
113
+ for (const rule of this.#peerRules) {
114
+ const peer = resolve(rule.peer, context);
115
+ if (rule.direction === "ingress") {
116
+ securityGroup.addIngressRule(peer, rule.port, rule.description);
117
+ }
118
+ else {
119
+ securityGroup.addEgressRule(peer, rule.port, rule.description);
120
+ }
121
+ }
122
+ for (const rule of this.#selfIngress) {
123
+ securityGroup.addIngressRule(securityGroup, rule.port, rule.description);
124
+ }
125
+ return { securityGroup };
126
+ }
127
+ }
128
+ /**
129
+ * Creates a new {@link ISecurityGroupBuilder} for configuring an AWS EC2
130
+ * security group.
131
+ *
132
+ * The returned builder exposes every {@link SecurityGroupBuilderProps}
133
+ * property as a fluent setter/getter, plus
134
+ * {@link ISecurityGroupBuilder.vpc | .vpc()} for cross-component VPC wiring
135
+ * and the `addIngressRule` / `addEgressRule` / `addSelfIngress` accumulators.
136
+ * It implements {@link Lifecycle} for use with {@link compose}.
137
+ *
138
+ * @returns A fluent builder for an AWS EC2 security group.
139
+ */
140
+ export function createSecurityGroupBuilder() {
141
+ return taggedBuilder(SecurityGroupBuilder);
142
+ }
143
+ //# sourceMappingURL=security-group-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-builder.js","sourceRoot":"","sources":["../../src/security-group-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { SecurityGroupProps } from "aws-cdk-lib/aws-ec2";
2
+ /**
3
+ * Secure, AWS-recommended defaults applied to every security group built
4
+ * with {@link createSecurityGroupBuilder}. Each property can be individually
5
+ * overridden via the builder's fluent API.
6
+ *
7
+ * Two properties intentionally have no default — they are application-
8
+ * specific and must be supplied explicitly:
9
+ * - `vpc` (via the builder's `.vpc()` method)
10
+ * - `description` (a short, human-readable summary of the SG's purpose)
11
+ */
12
+ export declare const SECURITY_GROUP_DEFAULTS: Partial<SecurityGroupProps>;
13
+ //# sourceMappingURL=security-group-defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-defaults.d.ts","sourceRoot":"","sources":["../../src/security-group-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,OAAO,CAAC,kBAAkB,CAY/D,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Secure, AWS-recommended defaults applied to every security group built
3
+ * with {@link createSecurityGroupBuilder}. Each property can be individually
4
+ * overridden via the builder's fluent API.
5
+ *
6
+ * Two properties intentionally have no default — they are application-
7
+ * specific and must be supplied explicitly:
8
+ * - `vpc` (via the builder's `.vpc()` method)
9
+ * - `description` (a short, human-readable summary of the SG's purpose)
10
+ */
11
+ export const SECURITY_GROUP_DEFAULTS = {
12
+ /**
13
+ * Closed-by-default egress. CDK's stock default is `true`, which creates
14
+ * an implicit `0.0.0.0/0` outbound rule on every SG — flagged by
15
+ * compliance scanners and incompatible with the project's least-privilege
16
+ * stance. Closing egress forces every outbound flow to be expressed as
17
+ * an explicit `addEgressRule` (or `.allowAllOutbound(true)` to opt back
18
+ * into the CDK default).
19
+ *
20
+ * @see https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_network_protection_layered.html
21
+ */
22
+ allowAllOutbound: false,
23
+ };
24
+ //# sourceMappingURL=security-group-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-group-defaults.js","sourceRoot":"","sources":["../../src/security-group-defaults.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAgC;IAClE;;;;;;;;;OASG;IACH,gBAAgB,EAAE,KAAK;CACxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@composurecdk/ec2",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Composable EC2 instance and VPC builders with well-architected defaults",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,15 +41,15 @@
41
41
  "@composurecdk/cloudwatch": "^0.8.0",
42
42
  "@composurecdk/core": "^0.8.0",
43
43
  "@composurecdk/logs": "^0.8.0",
44
- "aws-cdk-lib": "^2.0.0",
44
+ "aws-cdk-lib": "^2.54.0",
45
45
  "constructs": "^10.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/node": "^25.6.2",
49
- "aws-cdk-lib": "^2.253.1",
48
+ "@types/node": "^25.9.1",
49
+ "aws-cdk-lib": "^2.257.0",
50
50
  "constructs": "^10.6.0",
51
51
  "typescript": "^6.0.2",
52
- "vitest": "^4.1.2"
52
+ "vitest": "^4.1.7"
53
53
  },
54
54
  "exports": {
55
55
  "./package.json": "./package.json",