From 83848d6e8b2416e055440b54f33e9e41697f142e Mon Sep 17 00:00:00 2001 From: Yutaro Sakamoto Date: Sat, 5 Oct 2024 15:34:12 +0900 Subject: [PATCH 1/5] [Add]: add ecs cluster --- infrastructure/lib/constructs/ECS/index.ts | 54 +++++++++++++++++++ .../lib/constructs/Network/index.ts | 2 +- infrastructure/lib/main.ts | 7 ++- 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 infrastructure/lib/constructs/ECS/index.ts diff --git a/infrastructure/lib/constructs/ECS/index.ts b/infrastructure/lib/constructs/ECS/index.ts new file mode 100644 index 0000000..7e69a75 --- /dev/null +++ b/infrastructure/lib/constructs/ECS/index.ts @@ -0,0 +1,54 @@ +import { Construct } from "constructs"; +import * as ecs from "aws-cdk-lib/aws-ecs"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import { ApplicationLoadBalancedFargateService } from "aws-cdk-lib/aws-ecs-patterns"; +import { StackProps } from "aws-cdk-lib"; + +/** + * ECSのプロパティ + */ +export interface ECSProps extends StackProps { + /** + * ECSクラスタを作成するVPC + */ + vpc: ec2.Vpc; +} +/** + * ECSクラスタ + */ +export class ECS extends Construct { + constructor(scope: Construct, id: string, props: ECSProps) { + super(scope, id); + + // ECSクラスタを作成 + const cluster = new ecs.Cluster(this, "EcsCluster", { + vpc: props.vpc, + containerInsights: true, + }); + + const loadBalancedFargateService = + new ApplicationLoadBalancedFargateService(this, "Service", { + cluster, + memoryLimitMiB: 1024, + desiredCount: 1, + cpu: 512, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), + }, + }); + + const scalableTarget = + loadBalancedFargateService.service.autoScaleTaskCount({ + minCapacity: 1, + maxCapacity: 2, + }); + + scalableTarget.scaleOnCpuUtilization("CpuScaling", { + targetUtilizationPercent: 50, + }); + + scalableTarget.scaleOnMemoryUtilization("MemoryScaling", { + targetUtilizationPercent: 50, + }); + } +} diff --git a/infrastructure/lib/constructs/Network/index.ts b/infrastructure/lib/constructs/Network/index.ts index f1eb27e..7ef7066 100644 --- a/infrastructure/lib/constructs/Network/index.ts +++ b/infrastructure/lib/constructs/Network/index.ts @@ -18,7 +18,7 @@ export class Network extends Construct { // VPCを作成 this.vpc = new ec2.Vpc(this, "Vpc", { natGateways: 0, - createInternetGateway: false, + createInternetGateway: true, maxAzs: 2, subnetConfiguration: [ { diff --git a/infrastructure/lib/main.ts b/infrastructure/lib/main.ts index d58fd10..fb247b2 100644 --- a/infrastructure/lib/main.ts +++ b/infrastructure/lib/main.ts @@ -1,6 +1,7 @@ import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { Network } from "./constructs/Network"; +import { ECS } from "./constructs/ECS"; /** * スタック @@ -9,7 +10,11 @@ export class Cobol4JAwsWebStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); - new Network(this, "Network"); + const network = new Network(this, "Network"); + + new ECS(this, "ECS", { + vpc: network.vpc, + }); } /** From d4e47e49c49db2630d651df6e19980f3e054245e Mon Sep 17 00:00:00 2001 From: Yutaro Sakamoto Date: Sat, 5 Oct 2024 16:54:33 +0900 Subject: [PATCH 2/5] [Fix]: resolve cdk-nag errors --- infrastructure/bin/cobol4j-aws-web.ts | 6 ++- infrastructure/lib/constructs/ECS/index.ts | 37 +++++++++++++++++++ .../lib/constructs/Network/index.ts | 4 +- infrastructure/lib/main.ts | 6 ++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/infrastructure/bin/cobol4j-aws-web.ts b/infrastructure/bin/cobol4j-aws-web.ts index f3f725c..b084ee8 100644 --- a/infrastructure/bin/cobol4j-aws-web.ts +++ b/infrastructure/bin/cobol4j-aws-web.ts @@ -7,7 +7,11 @@ import { Aspects } from "aws-cdk-lib"; const app = new cdk.App(); Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true })); -const stack = new Cobol4JAwsWebStack(app, "StartCDKStack", {}); +const stack = new Cobol4JAwsWebStack(app, "StartCDKStack", { + env: { + region: "ap-northeast-1", + }, +}); // 必要に応じて作成するリソース全体に共通のタグを追加 // cdk.Tags.of(app).add("project", "StartCDKProject"); diff --git a/infrastructure/lib/constructs/ECS/index.ts b/infrastructure/lib/constructs/ECS/index.ts index 7e69a75..de03bff 100644 --- a/infrastructure/lib/constructs/ECS/index.ts +++ b/infrastructure/lib/constructs/ECS/index.ts @@ -1,8 +1,11 @@ import { Construct } from "constructs"; +import * as cdk from "aws-cdk-lib"; import * as ecs from "aws-cdk-lib/aws-ecs"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import { ApplicationLoadBalancedFargateService } from "aws-cdk-lib/aws-ecs-patterns"; import { StackProps } from "aws-cdk-lib"; +import * as s3 from "aws-cdk-lib/aws-s3"; +import { NagSuppressions } from "cdk-nag"; /** * ECSのプロパティ @@ -17,6 +20,8 @@ export interface ECSProps extends StackProps { * ECSクラスタ */ export class ECS extends Construct { + private logBucket: s3.Bucket; + constructor(scope: Construct, id: string, props: ECSProps) { super(scope, id); @@ -26,6 +31,7 @@ export class ECS extends Construct { containerInsights: true, }); + // Fargateサービスを作成 const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(this, "Service", { cluster, @@ -50,5 +56,36 @@ export class ECS extends Construct { scalableTarget.scaleOnMemoryUtilization("MemoryScaling", { targetUtilizationPercent: 50, }); + + this.logBucket = new s3.Bucket(this, "Bucket", { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + bucketName: "my-alb-bucket", + enforceSSL: true, + }); + + loadBalancedFargateService.loadBalancer.logAccessLogs(this.logBucket); + } + + /** + * NAGのチェックを抑制する + */ + public addCdkNagSuppressions(parentStack: cdk.Stack) { + NagSuppressions.addResourceSuppressionsByPath( + parentStack, + "/StartCDKStack/ECS/Service/LB/SecurityGroup/Resource", + [ + { + id: "AwsSolutions-EC23", + reason: "Security groups of web services allow large port ranges.", + }, + ], + ); + NagSuppressions.addResourceSuppressions(this.logBucket, [ + { + id: "AwsSolutions-S1", + reason: "ロギング用のバケットのアクセスログは不要", + }, + ]); } } diff --git a/infrastructure/lib/constructs/Network/index.ts b/infrastructure/lib/constructs/Network/index.ts index 7ef7066..6fd8ef6 100644 --- a/infrastructure/lib/constructs/Network/index.ts +++ b/infrastructure/lib/constructs/Network/index.ts @@ -23,8 +23,8 @@ export class Network extends Construct { subnetConfiguration: [ { cidrMask: 24, - name: "Private", - subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, + name: "Public", + subnetType: ec2.SubnetType.PUBLIC, }, ], }); diff --git a/infrastructure/lib/main.ts b/infrastructure/lib/main.ts index fb247b2..4cd0ad5 100644 --- a/infrastructure/lib/main.ts +++ b/infrastructure/lib/main.ts @@ -7,12 +7,14 @@ import { ECS } from "./constructs/ECS"; * スタック */ export class Cobol4JAwsWebStack extends cdk.Stack { + private ecsCluster: ECS; + constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const network = new Network(this, "Network"); - new ECS(this, "ECS", { + this.ecsCluster = new ECS(this, "ECS", { vpc: network.vpc, }); } @@ -21,6 +23,6 @@ export class Cobol4JAwsWebStack extends cdk.Stack { * NAGのチェックを抑制する */ public addCdkNagSuppressions() { - // 必要に応じてNag suppressionsを追加 + this.ecsCluster.addCdkNagSuppressions(this); } } From 56366878fe4c8705dc93b13beb25a346d890a5f0 Mon Sep 17 00:00:00 2001 From: Yutaro Sakamoto Date: Sat, 5 Oct 2024 17:01:50 +0900 Subject: [PATCH 3/5] [Add]: vpc endpoints * add VPC endpoints of ECR, ECRDocker, CloudWatch, S3 --- infrastructure/lib/constructs/Network/index.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/infrastructure/lib/constructs/Network/index.ts b/infrastructure/lib/constructs/Network/index.ts index 6fd8ef6..254e410 100644 --- a/infrastructure/lib/constructs/Network/index.ts +++ b/infrastructure/lib/constructs/Network/index.ts @@ -29,6 +29,24 @@ export class Network extends Construct { ], }); + // VPCエンドポイントを作成 + this.vpc.addInterfaceEndpoint("ECREndpoint", { + service: ec2.InterfaceVpcEndpointAwsService.ECR, + }); + + this.vpc.addInterfaceEndpoint("ECRDockerEndpoint", { + service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER, + }); + + this.vpc.addInterfaceEndpoint("CloudWatchEndpoint", { + service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS, + }); + + new ec2.GatewayVpcEndpoint(this, "S3Endpoint", { + service: ec2.GatewayVpcEndpointAwsService.S3, + vpc: this.vpc, + }); + // VPC Flow Logsを作成 const vpcFlowLogGroup = new logs.LogGroup(this, "VpcFlowLogGroup", { retention: logs.RetentionDays.THREE_DAYS, From b30d098f44a075ffa71136e75b026fbbc2fd126d Mon Sep 17 00:00:00 2001 From: Yutaro Sakamoto Date: Sat, 5 Oct 2024 17:20:23 +0900 Subject: [PATCH 4/5] [Add]: add tests --- infrastructure/test/cobol4j-aws-web.test.ts | 32 ++++++++++++++++++++ infrastructure/test/image-builder-4j.test.ts | 16 ---------- 2 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 infrastructure/test/cobol4j-aws-web.test.ts delete mode 100644 infrastructure/test/image-builder-4j.test.ts diff --git a/infrastructure/test/cobol4j-aws-web.test.ts b/infrastructure/test/cobol4j-aws-web.test.ts new file mode 100644 index 0000000..85a4a56 --- /dev/null +++ b/infrastructure/test/cobol4j-aws-web.test.ts @@ -0,0 +1,32 @@ +import * as cdk from "aws-cdk-lib"; +import { Template } from "aws-cdk-lib/assertions"; +import { Cobol4JAwsWebStack } from "../lib/main"; + +const app = new cdk.App(); +const stack = new Cobol4JAwsWebStack(app, "StartCDKStack", { + env: { + region: "ap-northeast-1", + }, +}); +const template = Template.fromStack(stack); + +test("No NAT Gateway", () => { + template.resourcePropertiesCountIs("AWS::EC2::NatGateway", {}, 0); +}); + +test("Internet Gateway", () => { + template.resourcePropertiesCountIs("AWS::EC2::InternetGateway", {}, 1); + template.resourcePropertiesCountIs( + "AWS::EC2::EgressOnlyInternetGateway", + {}, + 0, + ); +}); + +test("No ECR Repository", () => { + template.resourcePropertiesCountIs("AWS::ECR::Repository", {}, 0); +}); + +test("ECS Cluster", () => { + template.resourcePropertiesCountIs("AWS::ECS::Cluster", {}, 1); +}); diff --git a/infrastructure/test/image-builder-4j.test.ts b/infrastructure/test/image-builder-4j.test.ts deleted file mode 100644 index 90651a6..0000000 --- a/infrastructure/test/image-builder-4j.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -// import * as cdk from 'aws-cdk-lib'; -// import { Template } from 'aws-cdk-lib/assertions'; -// import * as ImageBuilder4J from '../lib/cobol4j-aws-web-stack'; - -// example test. To run these tests, uncomment this file along with the -// example resource in lib/cobol4j-aws-web-stack.ts -test("SQS Queue Created", () => { - // const app = new cdk.App(); - // // WHEN - // const stack = new ImageBuilder4J.ImageBuilder4JStack(app, 'MyTestStack'); - // // THEN - // const template = Template.fromStack(stack); - // template.hasResourceProperties('AWS::SQS::Queue', { - // VisibilityTimeout: 300 - // }); -}); From 2c324ccbd1c8554a4861a74c6ebcb80d9f8b1a33 Mon Sep 17 00:00:00 2001 From: Yutaro Sakamoto Date: Sat, 5 Oct 2024 17:23:52 +0900 Subject: [PATCH 5/5] [Update]: improve tests --- infrastructure/test/cobol4j-aws-web.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/test/cobol4j-aws-web.test.ts b/infrastructure/test/cobol4j-aws-web.test.ts index 85a4a56..61d3749 100644 --- a/infrastructure/test/cobol4j-aws-web.test.ts +++ b/infrastructure/test/cobol4j-aws-web.test.ts @@ -15,7 +15,7 @@ test("No NAT Gateway", () => { }); test("Internet Gateway", () => { - template.resourcePropertiesCountIs("AWS::EC2::InternetGateway", {}, 1); + template.hasResource("AWS::EC2::InternetGateway", {}); template.resourcePropertiesCountIs( "AWS::EC2::EgressOnlyInternetGateway", {}, @@ -28,5 +28,5 @@ test("No ECR Repository", () => { }); test("ECS Cluster", () => { - template.resourcePropertiesCountIs("AWS::ECS::Cluster", {}, 1); + template.hasResource("AWS::ECS::Cluster", {}); });