From 598f226339877d080484a3c2910011e00290f724 Mon Sep 17 00:00:00 2001 From: Akash Askoolum Date: Thu, 1 Apr 2021 17:14:27 +0100 Subject: [PATCH] feat: allow GuSecurityGroup to be specified at the app level --- src/constructs/autoscaling/asg.test.ts | 15 ++++++----- .../ec2/security-groups/base.test.ts | 12 ++++++--- src/constructs/ec2/security-groups/base.ts | 27 ++++++++++++++----- src/constructs/ec2/security-groups/wazuh.ts | 4 +-- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/constructs/autoscaling/asg.test.ts b/src/constructs/autoscaling/asg.test.ts index 3d967c4f29..784b5d537a 100644 --- a/src/constructs/autoscaling/asg.test.ts +++ b/src/constructs/autoscaling/asg.test.ts @@ -122,11 +122,12 @@ describe("The GuAutoScalingGroup", () => { }); test("adds any security groups passed through props", () => { + const app = "Testing"; const stack = simpleGuStackForTesting(); - const securityGroup = new GuSecurityGroup(stack, "SecurityGroup", { vpc, overrideId: true }); - const securityGroup1 = new GuSecurityGroup(stack, "SecurityGroup1", { vpc, overrideId: true }); - const securityGroup2 = new GuSecurityGroup(stack, "SecurityGroup2", { vpc, overrideId: true }); + const securityGroup = new GuSecurityGroup(stack, "SecurityGroup", { vpc, overrideId: true, app }); + const securityGroup1 = new GuSecurityGroup(stack, "SecurityGroup1", { vpc, overrideId: true, app }); + const securityGroup2 = new GuSecurityGroup(stack, "SecurityGroup2", { vpc, overrideId: true, app }); new GuAutoScalingGroup(stack, "AutoscalingGroup", { ...defaultProps, @@ -136,16 +137,16 @@ describe("The GuAutoScalingGroup", () => { expect(stack).toHaveResource("AWS::AutoScaling::LaunchConfiguration", { SecurityGroups: [ { - "Fn::GetAtt": ["GuHttpsEgressSecurityGroupF63CDA96", "GroupId"], + "Fn::GetAtt": [`GuHttpsEgressSecurityGroup${app}89CDDA4B`, "GroupId"], }, { - "Fn::GetAtt": ["SecurityGroup", "GroupId"], + "Fn::GetAtt": [`SecurityGroup${app}`, "GroupId"], }, { - "Fn::GetAtt": ["SecurityGroup1", "GroupId"], + "Fn::GetAtt": [`SecurityGroup1${app}`, "GroupId"], }, { - "Fn::GetAtt": ["SecurityGroup2", "GroupId"], + "Fn::GetAtt": [`SecurityGroup2${app}`, "GroupId"], }, ], }); diff --git a/src/constructs/ec2/security-groups/base.test.ts b/src/constructs/ec2/security-groups/base.test.ts index 7218c4d37c..130ffc7c07 100644 --- a/src/constructs/ec2/security-groups/base.test.ts +++ b/src/constructs/ec2/security-groups/base.test.ts @@ -16,16 +16,16 @@ describe("The GuSecurityGroup class", () => { it("overrides the id if the prop is set to true", () => { const stack = simpleGuStackForTesting(); - new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, overrideId: true }); + new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, overrideId: true, app: "testing" }); const json = SynthUtils.toCloudFormation(stack) as SynthedStack; - expect(Object.keys(json.Resources)).toContain("TestSecurityGroup"); + expect(Object.keys(json.Resources)).toContain("TestSecurityGroupTesting"); }); it("does not overrides the id if the prop is set to false", () => { const stack = simpleGuStackForTesting(); - new GuSecurityGroup(stack, "TestSecurityGroup", { vpc }); + new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, app: "testing" }); const json = SynthUtils.toCloudFormation(stack) as SynthedStack; expect(Object.keys(json.Resources)).not.toContain("TestSecurityGroup"); @@ -40,6 +40,7 @@ describe("The GuSecurityGroup class", () => { { range: Peer.ipv4("127.0.0.1/24"), description: "ingress1", port: 443 }, { range: Peer.ipv4("127.0.0.2/8"), description: "ingress2", port: 443 }, ], + app: "testing", }); expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { @@ -72,6 +73,7 @@ describe("The GuSecurityGroup class", () => { { range: Peer.ipv4("127.0.0.1/24"), port: Port.tcp(8000), description: "egress1" }, { range: Peer.ipv4("127.0.0.2/8"), port: Port.tcp(9000), description: "egress2" }, ], + app: "testing", }); expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { @@ -101,6 +103,7 @@ describe("The GuSecurityGroup class", () => { new GuSecurityGroup(stack, "TestSecurityGroup", { vpc, ingresses: [{ range: Peer.anyIpv4(), description: "SSH access", port: 22 }], + app: "testing", }); }).toThrow(new Error("An ingress rule on port 22 is not allowed. Prefer to setup SSH via SSM.")); }); @@ -118,6 +121,7 @@ describe("The GuPublicInternetAccessSecurityGroup class", () => { new GuPublicInternetAccessSecurityGroup(stack, "InternetAccessGroup", { vpc, + app: "testing", }); expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { @@ -145,7 +149,7 @@ describe("The GuHttpsEgressSecurityGroup class", () => { it("adds global access on 443 by default", () => { const stack = simpleGuStackForTesting(); - GuHttpsEgressSecurityGroup.forVpc(stack, { vpc }); + GuHttpsEgressSecurityGroup.forVpc(stack, { vpc, app: "testing" }); expect(stack).toHaveResource("AWS::EC2::SecurityGroup", { GroupDescription: "Allow all outbound HTTPS traffic", diff --git a/src/constructs/ec2/security-groups/base.ts b/src/constructs/ec2/security-groups/base.ts index 148ad58bef..0f3d402e43 100644 --- a/src/constructs/ec2/security-groups/base.ts +++ b/src/constructs/ec2/security-groups/base.ts @@ -1,6 +1,7 @@ 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 { AppIdentity } from "../../core/identity"; /** * A way to describe an ingress or egress rule for a security group. @@ -27,12 +28,14 @@ export interface SecurityGroupAccessRule { description: string; } -export interface GuSecurityGroupProps extends SecurityGroupProps { +export interface GuBaseSecurityGroupProps extends SecurityGroupProps { overrideId?: boolean; ingresses?: SecurityGroupAccessRule[]; egresses?: SecurityGroupAccessRule[]; } +export interface GuSecurityGroupProps extends GuBaseSecurityGroupProps, AppIdentity {} + /** * Defining an AWS Security Group with ingress and egress rules. * @@ -43,8 +46,8 @@ export interface GuSecurityGroupProps extends SecurityGroupProps { * - [[GuPublicInternetAccessSecurityGroup]] * - [[GuHttpsEgressSecurityGroup]] */ -export class GuSecurityGroup extends SecurityGroup { - constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { +export abstract class GuBaseSecurityGroup extends SecurityGroup { + protected constructor(scope: GuStack, id: string, props: GuBaseSecurityGroupProps) { super(scope, id, props); if (props.overrideId) { @@ -68,8 +71,16 @@ export class GuSecurityGroup extends SecurityGroup { } } +export class GuSecurityGroup extends GuBaseSecurityGroup { + constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { + super(scope, AppIdentity.suffixText(props, id), props); + AppIdentity.taggedConstruct(props, this); + } +} + +// TODO should this be a singleton? export class GuPublicInternetAccessSecurityGroup extends GuSecurityGroup { - constructor(scope: GuStack, id: string, props: SecurityGroupProps) { + constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { super(scope, id, { ...props, ingresses: [{ range: Peer.anyIpv4(), port: 443, description: "Allow all inbound traffic via HTTPS" }], @@ -78,17 +89,19 @@ export class GuPublicInternetAccessSecurityGroup extends GuSecurityGroup { } } +// TODO should this be a singleton? export class GuHttpsEgressSecurityGroup extends GuSecurityGroup { - constructor(scope: GuStack, id: string, props: SecurityGroupProps) { + constructor(scope: GuStack, id: string, props: GuSecurityGroupProps) { super(scope, id, { - vpc: props.vpc, + ...props, allowAllOutbound: false, description: "Allow all outbound HTTPS traffic", + ingresses: [], egresses: [{ range: Peer.anyIpv4(), port: 443, description: "Allow all outbound HTTPS traffic" }], }); } - public static forVpc(scope: GuStack, props: SecurityGroupProps): GuHttpsEgressSecurityGroup { + public static forVpc(scope: GuStack, props: GuSecurityGroupProps): GuHttpsEgressSecurityGroup { return new GuHttpsEgressSecurityGroup(scope, "GuHttpsEgressSecurityGroup", props); } } diff --git a/src/constructs/ec2/security-groups/wazuh.ts b/src/constructs/ec2/security-groups/wazuh.ts index 0e86b0e0c2..d6a8b0ee10 100644 --- a/src/constructs/ec2/security-groups/wazuh.ts +++ b/src/constructs/ec2/security-groups/wazuh.ts @@ -1,9 +1,9 @@ import type { IVpc } from "@aws-cdk/aws-ec2"; import { Peer } from "@aws-cdk/aws-ec2"; import type { GuStack } from "../../core"; -import { GuSecurityGroup } from "./base"; +import { GuBaseSecurityGroup } from "./base"; -export class GuWazuhAccess extends GuSecurityGroup { +export class GuWazuhAccess extends GuBaseSecurityGroup { private static instance: GuWazuhAccess | undefined; private constructor(scope: GuStack, vpc: IVpc) {