From 593d234b8a5026347461b73b53bb0b7666570683 Mon Sep 17 00:00:00 2001 From: Akash Askoolum Date: Thu, 1 Apr 2021 08:05:53 +0100 Subject: [PATCH 1/3] refactor: split security groups across multiple files --- .../base.test.ts} | 75 +------------------ .../base.ts} | 23 +----- src/constructs/ec2/security-groups/index.ts | 2 + .../ec2/security-groups/wazuh.test.ts | 69 +++++++++++++++++ src/constructs/ec2/security-groups/wazuh.ts | 25 +++++++ 5 files changed, 101 insertions(+), 93 deletions(-) rename src/constructs/ec2/{security-group.test.ts => security-groups/base.test.ts} (68%) rename src/constructs/ec2/{security-groups.ts => security-groups/base.ts} (81%) create mode 100644 src/constructs/ec2/security-groups/index.ts create mode 100644 src/constructs/ec2/security-groups/wazuh.test.ts create mode 100644 src/constructs/ec2/security-groups/wazuh.ts diff --git a/src/constructs/ec2/security-group.test.ts b/src/constructs/ec2/security-groups/base.test.ts similarity index 68% rename from src/constructs/ec2/security-group.test.ts rename to src/constructs/ec2/security-groups/base.test.ts index 93f6ccf33a..7218c4d37c 100644 --- a/src/constructs/ec2/security-group.test.ts +++ b/src/constructs/ec2/security-groups/base.test.ts @@ -1,15 +1,10 @@ -import { SynthUtils } from "@aws-cdk/assert"; import "@aws-cdk/assert/jest"; +import { SynthUtils } from "@aws-cdk/assert"; import { Peer, Port, Vpc } from "@aws-cdk/aws-ec2"; import { Stack } from "@aws-cdk/core"; -import { simpleGuStackForTesting } from "../../utils/test"; -import type { SynthedStack } from "../../utils/test"; -import { - GuHttpsEgressSecurityGroup, - GuPublicInternetAccessSecurityGroup, - GuSecurityGroup, - GuWazuhAccess, -} from "./security-groups"; +import { simpleGuStackForTesting } from "../../../utils/test"; +import type { SynthedStack } from "../../../utils/test"; +import { GuHttpsEgressSecurityGroup, GuPublicInternetAccessSecurityGroup, GuSecurityGroup } from "./base"; describe("The GuSecurityGroup class", () => { const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", { @@ -111,68 +106,6 @@ describe("The GuSecurityGroup class", () => { }); }); -describe("The GuWazuhAccess class", () => { - const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", { - vpcId: "test", - availabilityZones: [""], - publicSubnetIds: [""], - }); - - it("sets props as expected", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); - - expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { - GroupDescription: "Wazuh agent registration and event logging", - SecurityGroupEgress: [ - { - CidrIp: "0.0.0.0/0", - Description: "Wazuh event logging", - FromPort: 1514, - IpProtocol: "tcp", - ToPort: 1514, - }, - { - CidrIp: "0.0.0.0/0", - Description: "Wazuh agent registration", - FromPort: 1515, - IpProtocol: "tcp", - ToPort: 1515, - }, - ], - }); - }); - - it("merges default and passed in props", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, description: "This is a test" }); - - expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { - GroupDescription: "This is a test", - }); - }); - - it("overrides the id if the prop is set to true", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); - - const json = SynthUtils.toCloudFormation(stack) as SynthedStack; - expect(Object.keys(json.Resources)).toContain("WazuhSecurityGroup"); - }); - - it("does not overrides the id if the prop is set to false", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, overrideId: false }); - - const json = SynthUtils.toCloudFormation(stack) as SynthedStack; - expect(Object.keys(json.Resources)).not.toContain("WazuhSecurityGroup"); - }); -}); - describe("The GuPublicInternetAccessSecurityGroup class", () => { const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", { vpcId: "test", diff --git a/src/constructs/ec2/security-groups.ts b/src/constructs/ec2/security-groups/base.ts similarity index 81% rename from src/constructs/ec2/security-groups.ts rename to src/constructs/ec2/security-groups/base.ts index b5028cd1b1..148ad58bef 100644 --- a/src/constructs/ec2/security-groups.ts +++ b/src/constructs/ec2/security-groups/base.ts @@ -1,6 +1,6 @@ import type { CfnSecurityGroup, IPeer, SecurityGroupProps } from "@aws-cdk/aws-ec2"; import { Peer, Port, SecurityGroup } from "@aws-cdk/aws-ec2"; -import type { GuStack } from "../core"; +import type { GuStack } from "../../core"; /** * A way to describe an ingress or egress rule for a security group. @@ -68,27 +68,6 @@ export class GuSecurityGroup extends SecurityGroup { } } -export class GuWazuhAccess extends GuSecurityGroup { - private static getDefaultProps(): Partial { - return { - description: "Wazuh agent registration and event logging", - overrideId: true, - allowAllOutbound: false, - egresses: [ - { range: Peer.anyIpv4(), port: 1514, description: "Wazuh event logging" }, - { range: Peer.anyIpv4(), port: 1515, description: "Wazuh agent registration" }, - ], - }; - } - - constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { - super(scope, id, { - ...GuWazuhAccess.getDefaultProps(), - ...props, - }); - } -} - export class GuPublicInternetAccessSecurityGroup extends GuSecurityGroup { constructor(scope: GuStack, id: string, props: SecurityGroupProps) { super(scope, id, { diff --git a/src/constructs/ec2/security-groups/index.ts b/src/constructs/ec2/security-groups/index.ts new file mode 100644 index 0000000000..c2b8fbdac1 --- /dev/null +++ b/src/constructs/ec2/security-groups/index.ts @@ -0,0 +1,2 @@ +export * from "./base"; +export * from "./wazuh"; diff --git a/src/constructs/ec2/security-groups/wazuh.test.ts b/src/constructs/ec2/security-groups/wazuh.test.ts new file mode 100644 index 0000000000..70bc71c8f5 --- /dev/null +++ b/src/constructs/ec2/security-groups/wazuh.test.ts @@ -0,0 +1,69 @@ +import "@aws-cdk/assert/jest"; +import { SynthUtils } from "@aws-cdk/assert"; +import { Vpc } from "@aws-cdk/aws-ec2"; +import { Stack } from "@aws-cdk/core"; +import type { SynthedStack } from "../../../utils/test"; +import { simpleGuStackForTesting } from "../../../utils/test"; +import { GuWazuhAccess } from "./wazuh"; + +describe("The GuWazuhAccess class", () => { + const vpc = Vpc.fromVpcAttributes(new Stack(), "VPC", { + vpcId: "test", + availabilityZones: [""], + publicSubnetIds: [""], + }); + + it("sets props as expected", () => { + const stack = simpleGuStackForTesting(); + + new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); + + expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { + GroupDescription: "Wazuh agent registration and event logging", + SecurityGroupEgress: [ + { + CidrIp: "0.0.0.0/0", + Description: "Wazuh event logging", + FromPort: 1514, + IpProtocol: "tcp", + ToPort: 1514, + }, + { + CidrIp: "0.0.0.0/0", + Description: "Wazuh agent registration", + FromPort: 1515, + IpProtocol: "tcp", + ToPort: 1515, + }, + ], + }); + }); + + it("merges default and passed in props", () => { + const stack = simpleGuStackForTesting(); + + new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, description: "This is a test" }); + + expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { + GroupDescription: "This is a test", + }); + }); + + it("overrides the id if the prop is set to true", () => { + const stack = simpleGuStackForTesting(); + + new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); + + const json = SynthUtils.toCloudFormation(stack) as SynthedStack; + expect(Object.keys(json.Resources)).toContain("WazuhSecurityGroup"); + }); + + it("does not overrides the id if the prop is set to false", () => { + const stack = simpleGuStackForTesting(); + + new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, overrideId: false }); + + const json = SynthUtils.toCloudFormation(stack) as SynthedStack; + expect(Object.keys(json.Resources)).not.toContain("WazuhSecurityGroup"); + }); +}); diff --git a/src/constructs/ec2/security-groups/wazuh.ts b/src/constructs/ec2/security-groups/wazuh.ts new file mode 100644 index 0000000000..6aa03fd174 --- /dev/null +++ b/src/constructs/ec2/security-groups/wazuh.ts @@ -0,0 +1,25 @@ +import { Peer } from "@aws-cdk/aws-ec2"; +import type { GuStack } from "../../core"; +import type { GuSecurityGroupProps } from "./base"; +import { GuSecurityGroup } from "./base"; + +export class GuWazuhAccess extends GuSecurityGroup { + private static getDefaultProps(): Partial { + return { + description: "Wazuh agent registration and event logging", + overrideId: true, + allowAllOutbound: false, + egresses: [ + { range: Peer.anyIpv4(), port: 1514, description: "Wazuh event logging" }, + { range: Peer.anyIpv4(), port: 1515, description: "Wazuh agent registration" }, + ], + }; + } + + constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { + super(scope, id, { + ...GuWazuhAccess.getDefaultProps(), + ...props, + }); + } +} From 671238446ec85279a1a477fc08141d8a564a62fa Mon Sep 17 00:00:00 2001 From: Akash Askoolum Date: Thu, 1 Apr 2021 08:21:53 +0100 Subject: [PATCH 2/3] chore: fix typo --- src/constructs/iam/policies/log-shipping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constructs/iam/policies/log-shipping.ts b/src/constructs/iam/policies/log-shipping.ts index b0913fce92..dc2107f728 100644 --- a/src/constructs/iam/policies/log-shipping.ts +++ b/src/constructs/iam/policies/log-shipping.ts @@ -17,7 +17,7 @@ export class GuLogShippingPolicy extends GuAllowPolicy { } public static getInstance(stack: GuStack): GuLogShippingPolicy { - // Resources can only live in the same App so return a new `GuSSMRunCommandPolicy` where necessary. + // Resources can only live in the same App so return a new instance where necessary. // See https://github.com/aws/aws-cdk/blob/0ea4b19afd639541e5f1d7c1783032ee480c307e/packages/%40aws-cdk/core/lib/private/refs.ts#L47-L50 const isSameStack = this.instance?.node.root === stack.node.root; From 742c6749cd2475a2ab204cccede8869b7d4d6a4a Mon Sep 17 00:00:00 2001 From: Akash Askoolum Date: Thu, 1 Apr 2021 08:26:36 +0100 Subject: [PATCH 3/3] feat: make Wazuh access security group a singleton We'd only ever want one of these resources defined in a stack as it can be re-used by anything that needs it. This helps keep the overall size of the template down and thus reduces chance of reaching the file size limits of cloudformation. --- .../ec2/security-groups/wazuh.test.ts | 32 +------------------ src/constructs/ec2/security-groups/wazuh.ts | 26 +++++++++------ 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/constructs/ec2/security-groups/wazuh.test.ts b/src/constructs/ec2/security-groups/wazuh.test.ts index 70bc71c8f5..24c694b925 100644 --- a/src/constructs/ec2/security-groups/wazuh.test.ts +++ b/src/constructs/ec2/security-groups/wazuh.test.ts @@ -1,8 +1,6 @@ import "@aws-cdk/assert/jest"; -import { SynthUtils } from "@aws-cdk/assert"; import { Vpc } from "@aws-cdk/aws-ec2"; import { Stack } from "@aws-cdk/core"; -import type { SynthedStack } from "../../../utils/test"; import { simpleGuStackForTesting } from "../../../utils/test"; import { GuWazuhAccess } from "./wazuh"; @@ -16,7 +14,7 @@ describe("The GuWazuhAccess class", () => { it("sets props as expected", () => { const stack = simpleGuStackForTesting(); - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); + GuWazuhAccess.getInstance(stack, vpc); expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { GroupDescription: "Wazuh agent registration and event logging", @@ -38,32 +36,4 @@ describe("The GuWazuhAccess class", () => { ], }); }); - - it("merges default and passed in props", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, description: "This is a test" }); - - expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { - GroupDescription: "This is a test", - }); - }); - - it("overrides the id if the prop is set to true", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc }); - - const json = SynthUtils.toCloudFormation(stack) as SynthedStack; - expect(Object.keys(json.Resources)).toContain("WazuhSecurityGroup"); - }); - - it("does not overrides the id if the prop is set to false", () => { - const stack = simpleGuStackForTesting(); - - new GuWazuhAccess(stack, "WazuhSecurityGroup", { vpc, overrideId: false }); - - const json = SynthUtils.toCloudFormation(stack) as SynthedStack; - expect(Object.keys(json.Resources)).not.toContain("WazuhSecurityGroup"); - }); }); diff --git a/src/constructs/ec2/security-groups/wazuh.ts b/src/constructs/ec2/security-groups/wazuh.ts index 6aa03fd174..0e86b0e0c2 100644 --- a/src/constructs/ec2/security-groups/wazuh.ts +++ b/src/constructs/ec2/security-groups/wazuh.ts @@ -1,11 +1,14 @@ +import type { IVpc } from "@aws-cdk/aws-ec2"; import { Peer } from "@aws-cdk/aws-ec2"; import type { GuStack } from "../../core"; -import type { GuSecurityGroupProps } from "./base"; import { GuSecurityGroup } from "./base"; export class GuWazuhAccess extends GuSecurityGroup { - private static getDefaultProps(): Partial { - return { + private static instance: GuWazuhAccess | undefined; + + private constructor(scope: GuStack, vpc: IVpc) { + super(scope, "WazuhSecurityGroup", { + vpc, description: "Wazuh agent registration and event logging", overrideId: true, allowAllOutbound: false, @@ -13,13 +16,18 @@ export class GuWazuhAccess extends GuSecurityGroup { { range: Peer.anyIpv4(), port: 1514, description: "Wazuh event logging" }, { range: Peer.anyIpv4(), port: 1515, description: "Wazuh agent registration" }, ], - }; + }); } - constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { - super(scope, id, { - ...GuWazuhAccess.getDefaultProps(), - ...props, - }); + public static getInstance(stack: GuStack, vpc: IVpc): GuWazuhAccess { + // Resources can only live in the same App so return a new instance where necessary. + // See https://github.com/aws/aws-cdk/blob/0ea4b19afd639541e5f1d7c1783032ee480c307e/packages/%40aws-cdk/core/lib/private/refs.ts#L47-L50 + const isSameStack = this.instance?.node.root === stack.node.root; + + if (!this.instance || !isSameStack) { + this.instance = new GuWazuhAccess(stack, vpc); + } + + return this.instance; } }