From f8fdc4fca88a59591c396adfb39dd78d7658213d Mon Sep 17 00:00:00 2001 From: James Mead Date: Sun, 8 Mar 2020 14:12:20 +0000 Subject: [PATCH] fix(aws-ecs-pattern): allow ScheduledTaskBase to run on a public subnet Allow instances of ScheduledFargateTask and ScheduledEc2Task to run in a *public* subnet via a configuration option. The default remains that such instances are restricted to run on private subnets, but it is now possible to allow them to run on public subnets if the user is willing to sacrifice the extra security that a private subnet provides in favour of a simpler/cheaper system that does not require a NAT gateway or a NAT instance. The new unit test schedules a Fargate task to run on a container in a VPC with no private subnet. Before the changes to ScheduledTaskBase in this commit, this test caused the following error: Error: There are no 'Private' subnet groups in this VPC. Available types: Public fixes #6312 --- .../lib/base/scheduled-task-base.ts | 24 +++++++++- .../fargate/test.scheduled-fargate-task.ts | 45 ++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index 315f03066fae4..f71aa1126a4f0 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -1,5 +1,5 @@ import { Schedule } from "@aws-cdk/aws-applicationautoscaling"; -import { IVpc } from '@aws-cdk/aws-ec2'; +import { IVpc, SubnetSelection, SubnetType } from '@aws-cdk/aws-ec2'; import { AwsLogDriver, Cluster, ContainerImage, ICluster, LogDriver, Secret, TaskDefinition } from "@aws-cdk/aws-ecs"; import { Rule } from "@aws-cdk/aws-events"; import { EcsTask } from "@aws-cdk/aws-events-targets"; @@ -39,6 +39,15 @@ export interface ScheduledTaskBaseProps { * @default 1 */ readonly desiredTaskCount?: number; + + /** + * In what subnets to place the task's ENIs + * + * (Only applicable in case the TaskDefinition is configured for AwsVpc networking) + * + * @default Private subnets + */ + readonly subnetSelection?: SubnetSelection; } export interface ScheduledTaskImageProps { @@ -95,6 +104,15 @@ export abstract class ScheduledTaskBase extends Construct { */ public readonly desiredTaskCount: number; + /** + * In what subnets to place the task's ENIs + * + * (Only applicable in case the TaskDefinition is configured for AwsVpc networking) + * + * @default Private subnets + */ + public readonly subnetSelection: SubnetSelection; + /** * The CloudWatch Events rule for the service. */ @@ -111,6 +129,7 @@ export abstract class ScheduledTaskBase extends Construct { throw new Error('You must specify a desiredTaskCount greater than 0'); } this.desiredTaskCount = props.desiredTaskCount || 1; + this.subnetSelection = props.subnetSelection || { subnetType: SubnetType.PRIVATE }; // An EventRule that describes the event trigger (in this case a scheduled run) this.eventRule = new Rule(this, 'ScheduledEventRule', { @@ -128,7 +147,8 @@ export abstract class ScheduledTaskBase extends Construct { const eventRuleTarget = new EcsTask( { cluster: this.cluster, taskDefinition, - taskCount: this.desiredTaskCount + taskCount: this.desiredTaskCount, + subnetSelection: this.subnetSelection }); this.eventRule.addTarget(eventRuleTarget); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts index 121937ab9c750..cb62d40ef7e3f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts @@ -1,4 +1,4 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; @@ -251,4 +251,47 @@ export = { test.done(); }, + + "Scheduled Fargate Task - with subnetSelection defined"(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 1, + subnetConfiguration: [ + { name: 'Public', cidrMask: 28, subnetType: ec2.SubnetType.PUBLIC } + ], + }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + }, + subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, + schedule: events.Schedule.expression('rate(1 minute)') + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Targets: [ + { + EcsParameters: { + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'ENABLED', + Subnets: [ + { + Ref: 'VpcPublicSubnet1Subnet5C2D37C4' + } + ] + } + }, + } + } + ] + })); + + test.done(); + }, };