in source/lib/ecs-finder-stack.ts [52:214]
constructor(scope: Construct, id: string, props: EcsTaskProps) {
super(scope, id);
const ecrRegistry = process.env.PUBLIC_ECR_REGISTRY || 'public.ecr.aws/aws-gcr-solutions'
const ecrImageName = 'data-transfer-hub-cli'
const ecrImageTag = process.env.PUBLIC_ECR_TAG || props.cliRelease
const ecrImageUrl = `${ecrRegistry}/${ecrImageName}:${ecrImageTag}`
const ecsLG = new LogGroup(this, 'FinderLogGroup', {
retention: RetentionDays.TWO_WEEKS,
// removalPolicy: RemovalPolicy.DESTROY
});
const cfnEcsLG = ecsLG.node.defaultChild as CfnLogGroup
addCfnNagSuppressRules(cfnEcsLG, [
{
id: 'W84',
reason: 'log group is encrypted with the default master key'
}
])
this.taskDefinition = new ecs.FargateTaskDefinition(this, 'JobFinderTaskDef', {
cpu: props.cpu ? props.cpu : 1024 * 4,
memoryLimitMiB: props.memory ? props.memory : 1024 * 8,
family: `${Aws.STACK_NAME}-DTHFinderTask`,
});
this.taskDefinition.addContainer('DefaultContainer', {
image: ecs.ContainerImage.fromRegistry(ecrImageUrl),
environment: props.env,
logging: ecs.LogDrivers.awsLogs({
streamPrefix: 'ecsJobSender',
logGroup: ecsLG,
})
});
const cluster = ecs.Cluster.fromClusterAttributes(this, 'ECSCluster', {
clusterName: props.ecsClusterName,
vpc: props.vpc,
securityGroups: []
})
this.securityGroup = new ec2.SecurityGroup(this, 'S3RepECSSG', {
vpc: props.vpc,
description: `Security Group for running ${Aws.STACK_NAME}-DTHFinderTask`,
allowAllOutbound: true
});
const cfnSG = this.securityGroup.node.defaultChild as ec2.CfnSecurityGroup
addCfnNagSuppressRules(cfnSG, [
{
id: 'W5',
reason: 'Open egress rule is required to access public network'
},
{
id: 'W40',
reason: 'Open egress rule is required to access public network'
},
])
// 8. CloudWatch Rule.
// Schedule CRON event to trigger JobSender per hour
const trigger = new events.Rule(this, 'DTHFinderSchedule', {
schedule: events.Schedule.rate(Duration.hours(1)),
})
// Add target to cloudwatch rule.
trigger.addTarget(new targets.EcsTask({
cluster: cluster,
taskDefinition: this.taskDefinition,
taskCount: 1,
subnetSelection: {
subnetType: ec2.SubnetType.PUBLIC,
},
securityGroups: [this.securityGroup]
}));
const onEventHandler = new lambda.Function(this, 'EventHandler', {
runtime: lambda.Runtime.PYTHON_3_8,
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
handler: 'lambda_event_handler.lambda_handler',
memorySize: 256,
timeout: Duration.minutes(15),
});
const cfnFn = onEventHandler.node.defaultChild as lambda.CfnFunction
addCfnNagSuppressRules(cfnFn, [
{
id: 'W58',
reason: 'False alarm: The Lambda function does have the permission to write CloudWatch Logs.'
}, {
id: 'W92',
reason: 'No concurrencies required for this function'
}, {
id: 'W89',
reason: 'This function does not need to be deployed in a VPC'
}
])
onEventHandler.node.addDependency(this.taskDefinition)
const taskDefArnNoVersion = Stack.of(this).formatArn({
service: 'ecs',
resource: 'task-definition',
resourceName: this.taskDefinition.family
})
const ecsTaskPolicy = new iam.Policy(this, 'ECSTaskPolicy', {
statements: [
new iam.PolicyStatement({
actions: ['ecs:ListTasks'],
effect: iam.Effect.ALLOW,
resources: ['*']
}),
new iam.PolicyStatement({
actions: ['ecs:RunTask'],
effect: iam.Effect.ALLOW,
resources: [taskDefArnNoVersion]
})
]
});
const cfnEcsTaskPolicy = ecsTaskPolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfnEcsTaskPolicy, [
{
id: 'W12',
reason: 'List Task Action requires any resources'
},
])
onEventHandler.role?.attachInlinePolicy(ecsTaskPolicy)
this.taskDefinition.taskRole.grantPassRole(onEventHandler.grantPrincipal)
this.taskDefinition.executionRole?.grantPassRole(onEventHandler.grantPrincipal)
const lambdaProvider = new cr.Provider(this, 'Provider', {
onEventHandler: onEventHandler,
});
lambdaProvider.node.addDependency(this.taskDefinition)
const ecsCr = new CustomResource(this, 'DRHS3CustomResource', {
serviceToken: lambdaProvider.serviceToken,
properties: {
'cluster_name': props.ecsClusterName,
'family': this.taskDefinition.family,
'subnets': props.ecsSubnetIds,
'security_group': this.securityGroup.securityGroupName,
'stack_name': Aws.STACK_NAME,
}
});
ecsCr.node.addDependency(lambdaProvider, this.taskDefinition)
new CfnOutput(this, 'TaskDefinitionName', {
value: this.taskDefinition.family,
description: 'Task Definition Name'
})
}