in source/lib/aws-data-replication-component-ecr-stack.ts [76:780]
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
const sourceType = new cdk.CfnParameter(this, 'sourceType', {
description: 'Choose type of source container registry, for example Amazon_ECR, or Public from Docker Hub, gco.io, etc.',
type: 'String',
default: 'Amazon_ECR',
allowedValues: ['Amazon_ECR', 'Public']
})
this.addToParamLabels('Source Type', sourceType.logicalId)
// Only required for ECR
const srcRegion = new cdk.CfnParameter(this, 'srcRegion', {
description: 'Source Region Name (only required if source type is Amazon ECR), for example, us-west-1',
type: 'String',
default: '',
})
this.addToParamLabels('Source Region Name', srcRegion.logicalId)
// Only required for ECR
const srcAccountId = new cdk.CfnParameter(this, 'srcAccountId', {
description: 'Source AWS Account ID (only required if source type is Amazon ECR), leave it blank if source is in current account',
type: 'String',
default: '',
})
this.addToParamLabels('Source AWS Account ID', srcAccountId.logicalId)
//
const srcList = new cdk.CfnParameter(this, 'srcList', {
description: 'Type of Source Image List, either ALL or SELECTED, for public registry, please use SELECTED only',
type: 'String',
default: 'ALL',
allowedValues: ['ALL', 'SELECTED']
})
this.addToParamLabels('Source Image List Type', srcList.logicalId)
const srcImageList = new cdk.CfnParameter(this, 'srcImageList', {
description: 'Selected Image List delimited by comma, for example, ubuntu:latest,alpine:latest..., leave it blank if Type is ALL',
type: 'String',
default: '',
})
this.addToParamLabels('Source Image List', srcImageList.logicalId)
// Currently, only required if source type is ECR
const srcCredential = new cdk.CfnParameter(this, 'srcCredential', {
description: 'The secret name in Secrets Manager only when using AK/SK credentials to pull images from source Amazon ECR, leave it blank for public registry',
type: 'String',
default: '',
})
this.addToParamLabels('Source Credentials', srcCredential.logicalId)
const destRegion = new cdk.CfnParameter(this, 'destRegion', {
description: 'Destination Region Name, for example, cn-north-1',
type: 'String',
})
this.addToParamLabels('Destination Region Name', destRegion.logicalId)
const destAccountId = new cdk.CfnParameter(this, 'destAccountId', {
description: 'Destination AWS Account ID, leave it blank if destination is in current account',
type: 'String',
default: '',
})
this.addToParamLabels('Destination AWS Account ID', destAccountId.logicalId)
const destPrefix = new cdk.CfnParameter(this, 'destPrefix', {
description: 'Destination Repo Prefix',
type: 'String',
default: '',
})
this.addToParamLabels('Destination Repo Prefix', destPrefix.logicalId)
const destCredential = new cdk.CfnParameter(this, 'destCredential', {
description: 'The secret name in Secrets Manager only when using AK/SK credentials to push images to destination Amazon ECR',
type: 'String',
default: '',
})
this.addToParamLabels('Destination Credentials', destCredential.logicalId)
const ecsClusterName = new cdk.CfnParameter(this, 'ecsClusterName', {
description: 'ECS Cluster Name to run ECS task (Please make sure the cluster exists)',
type: 'String'
})
this.addToParamLabels('ECS Cluster Name', ecsClusterName.logicalId)
const ecsVpcId = new cdk.CfnParameter(this, 'ecsVpcId', {
description: 'VPC ID to run ECS task, e.g. vpc-bef13dc7',
type: 'AWS::EC2::VPC::Id'
})
this.addToParamLabels('VPC ID', ecsVpcId.logicalId)
const ecsSubnetA = new cdk.CfnParameter(this, 'ecsSubnetA', {
description: 'First Subnet ID to run ECS task, e.g. subnet-97bfc4cd',
type: 'AWS::EC2::Subnet::Id'
})
this.addToParamLabels('First Subnet ID', ecsSubnetA.logicalId)
const ecsSubnetB = new cdk.CfnParameter(this, 'ecsSubnetB', {
description: 'Second Subnet ID to run ECS task, e.g. subnet-7ad7de32',
type: 'AWS::EC2::Subnet::Id'
})
this.addToParamLabels('Second Subnet ID', ecsSubnetB.logicalId)
const alarmEmail = new cdk.CfnParameter(this, 'alarmEmail', {
description: 'Alarm Email address to receive notification in case of any failure',
// default: '',
allowedPattern: '\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}',
type: 'String',
})
this.addToParamLabels('Alarm Email', alarmEmail.logicalId)
this.addToParamGroups('Type', sourceType.logicalId)
this.addToParamGroups('Source Information', srcRegion.logicalId, srcAccountId.logicalId, srcList.logicalId, srcImageList.logicalId, srcCredential.logicalId)
this.addToParamGroups('Destination Information', destRegion.logicalId, destAccountId.logicalId, destPrefix.logicalId, destCredential.logicalId)
this.addToParamGroups('ECS Cluster Information', ecsClusterName.logicalId, ecsVpcId.logicalId, ecsSubnetA.logicalId, ecsSubnetB.logicalId)
this.addToParamGroups('Notification Information', alarmEmail.logicalId)
this.templateOptions.description = `(SO8003) - Data Transfer Hub - ECR Plugin - Template version ${VERSION}`;
this.templateOptions.metadata = {
'AWS::CloudFormation::Interface': {
ParameterGroups: this.paramGroups,
ParameterLabels: this.paramLabels,
}
}
const isSelectedImage = new cdk.CfnCondition(this, 'isSelectedImage', {
expression: cdk.Fn.conditionEquals('SELECTED', srcList),
});
const isSrcInCurrentAccount = new cdk.CfnCondition(this, 'isSrcInCurrentAccount', {
expression: cdk.Fn.conditionAnd(
// Source Account ID is blank
cdk.Fn.conditionEquals('', srcAccountId),
// Source Type is Amazon ECR
cdk.Fn.conditionEquals('Amazon_ECR', sourceType)),
});
const isDestInCurrentAccount = new cdk.CfnCondition(this, 'isDestInCurrentAccount', {
// Destination in Current Account
expression: cdk.Fn.conditionEquals('', destAccountId),
});
const selectedImages = cdk.Fn.conditionIf(isSelectedImage.logicalId, srcImageList.valueAsString, 'Not Applicable').toString();
// Set up SSM for selected image list
const selectedImageParam = new ssm.StringParameter(this, 'selectedImageParam', {
description: `Parameter to store the selected image list delimited by comma for stack ${cdk.Aws.STACK_NAME}`,
// parameterName: 'SelectedImageList',
stringValue: selectedImages,
});
// Setup DynamoDB
const imageTable = new ddb.Table(this, 'ECRTransferTable', {
partitionKey: { name: 'Image', type: ddb.AttributeType.STRING },
sortKey: { name: 'Tag', type: ddb.AttributeType.STRING },
billingMode: ddb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
pointInTimeRecovery: true,
})
const cfnTable = imageTable.node.defaultChild as ddb.CfnTable
addCfnNagSuppressRules(cfnTable, [
{
id: 'W74',
reason: 'This table is set to use DEFAULT encryption, the key is owned by DDB.'
},
])
const listImagesLambda = new lambda.Function(this, 'ListImagesFunction', {
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
memorySize: 256,
timeout: cdk.Duration.minutes(15),
// tracing: lambda.Tracing.ACTIVE,
environment: {
SOURCE_TYPE: sourceType.valueAsString,
SRC_ACCOUNT_ID: srcAccountId.valueAsString,
SRC_LIST: srcList.valueAsString,
SRC_REGION: srcRegion.valueAsString,
SRC_CREDENTIAL_NAME: srcCredential.valueAsString,
SELECTED_IMAGE_PARAM: selectedImageParam.parameterName,
}
});
const srcSecretParam = secretsmanager.Secret.fromSecretNameV2(this, 'srcSecretParam', srcCredential.valueAsString);
const desSecretParam = secretsmanager.Secret.fromSecretNameV2(this, 'desSecretParam', destCredential.valueAsString);
listImagesLambda.addToRolePolicy(
new iam.PolicyStatement({
actions: [
"ecr:DescribeRepositories",
"ecr:DescribeImages",
],
resources: [
`arn:${cdk.Aws.PARTITION}:ecr:${srcRegion.valueAsString}:${cdk.Aws.ACCOUNT_ID}:repository/*`
]
})
);
selectedImageParam.grantRead(listImagesLambda);
srcSecretParam.grantRead(listImagesLambda);
const vpc = ec2.Vpc.fromVpcAttributes(this, 'ECSVpc', {
vpcId: ecsVpcId.valueAsString,
availabilityZones: cdk.Fn.getAzs(),
publicSubnetIds: [ecsSubnetA.valueAsString, ecsSubnetB.valueAsString]
})
const cluster = ecs.Cluster.fromClusterAttributes(this, 'ECSCluster', {
clusterName: ecsClusterName.valueAsString,
vpc: vpc,
securityGroups: []
})
const containerlogGroup = new logs.LogGroup(this, `DTH-ECR-Container-LogGroup`, {
retention: 365
});
const cfncontainerlogGroup = containerlogGroup.node.defaultChild as logs.CfnLogGroup
addCfnNagSuppressRules(cfncontainerlogGroup, [
{
id: 'W84',
reason: 'Log group data is always encrypted in CloudWatch Logs using an AWS Managed KMS Key'
},
])
// Create ECS executionRole and executionPolicy
const ecsTaskExecutionRole = new iam.Role(this, `DTH-ECR-TaskExecutionRole`, {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com')
});
const taskExecutionPolicy = new iam.Policy(this, 'TaskExecutionPolicy', {
policyName: `${cdk.Aws.STACK_NAME}TaskExecutionPolicy`,
statements: [
new iam.PolicyStatement({
actions: [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
resources: [
containerlogGroup.logGroupArn
]
}),
]
});
taskExecutionPolicy.node.addDependency(containerlogGroup);
taskExecutionPolicy.attachToRole(ecsTaskExecutionRole);
const taskDefinition = new ecs.TaskDefinition(this, 'ECRTransferTask', {
memoryMiB: '1024',
cpu: '512',
compatibility: ecs.Compatibility.FARGATE,
family: `${cdk.Aws.STACK_NAME}-ECRTransferTask`,
executionRole: ecsTaskExecutionRole.withoutPolicyUpdates()
});
srcSecretParam.grantRead(taskDefinition.taskRole);
desSecretParam.grantRead(taskDefinition.taskRole);
const ecrRegistry = process.env.PUBLIC_ECR_REGISTRY || 'public.ecr.aws/aws-gcr-solutions'
const ecrImageName = 'data-transfer-hub-ecr'
const ecrImageTag = process.env.PUBLIC_ECR_TAG || VERSION
const ecrImageUrl = `${ecrRegistry}/${ecrImageName}:${ecrImageTag}`
const containerDefinition = taskDefinition.addContainer('DefaultContainer', {
image: ecs.ContainerImage.fromRegistry(ecrImageUrl),
environment: {
SOURCE_TYPE: sourceType.valueAsString,
AWS_DEFAULT_REGION: this.region,
AWS_ACCOUNT_ID: this.account,
SRC_REGION: srcRegion.valueAsString,
SRC_ACCOUNT_ID: srcAccountId.valueAsString,
SRC_CREDENTIAL_NAME: srcCredential.valueAsString,
DEST_REGION: destRegion.valueAsString,
DEST_ACCOUNT_ID: destAccountId.valueAsString,
DEST_PREFIX: destPrefix.valueAsString,
DEST_CREDENTIAL_NAME: destCredential.valueAsString,
},
logging: ecs.LogDrivers.awsLogs({
streamPrefix: 'DTH-ECR',
logGroup: containerlogGroup,
})
});
const ecrSrcReadOnlyPolicy = new iam.Policy(this, 'ECRSrcReadOnlyPolicy', {
policyName: `${cdk.Aws.STACK_NAME}ECRSrcReadOnlyPolicy`,
statements: [
new iam.PolicyStatement({
actions: [
"ecr:GetAuthorizationToken",
],
resources: [
'*'
]
}),
new iam.PolicyStatement({
actions: [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
],
resources: [
`arn:${cdk.Aws.PARTITION}:ecr:${srcRegion.valueAsString}:${cdk.Aws.ACCOUNT_ID}:repository/*`
]
}),
]
});
const cfnecrSrcReadOnlyPolicy = ecrSrcReadOnlyPolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfnecrSrcReadOnlyPolicy, [
{
id: 'W12',
reason: 'This IAM policy need * resource'
},
])
const ecrSrcPolicy = ecrSrcReadOnlyPolicy.node.defaultChild as iam.CfnPolicy
ecrSrcPolicy.cfnOptions.condition = isSrcInCurrentAccount
ecrSrcReadOnlyPolicy.attachToRole(taskDefinition.taskRole);
const ecrDestWritePolicy = new iam.Policy(this, 'ECRDestWritePolicy', {
policyName: `${cdk.Aws.STACK_NAME}ECRDestWritePolicy`,
statements: [
new iam.PolicyStatement({
actions: [
"ecr:GetAuthorizationToken",
],
resources: [
'*'
]
}),
new iam.PolicyStatement({
actions: [
"ecr:CreateRepository",
"ecr:CompleteLayerUpload",
"ecr:UploadLayerPart",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
],
resources: [
`arn:${cdk.Aws.PARTITION}:ecr:${destRegion.valueAsString}:${cdk.Aws.ACCOUNT_ID}:repository/*`
]
}),
]
});
const cfnecrDestWritePolicy = ecrDestWritePolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfnecrDestWritePolicy, [
{
id: 'W12',
reason: 'This IAM policy need * resource'
},
])
const ecrDestPolicy = ecrDestWritePolicy.node.defaultChild as iam.CfnPolicy
ecrDestPolicy.cfnOptions.condition = isDestInCurrentAccount
ecrDestWritePolicy.attachToRole(taskDefinition.taskRole);
const submitJob = new tasks.LambdaInvoke(this, 'Submit Lambda', {
lambdaFunction: listImagesLambda,
// Lambda's result is in the attribute `Payload`
outputPath: '$.Payload'
});
const clusterSG = new ec2.SecurityGroup(this, 'clusterSG', {
allowAllOutbound: true,
description: `SG for ${cdk.Aws.STACK_NAME} Fargate Tasks`,
vpc: vpc,
});
const cfnclusterSG = clusterSG.node.defaultChild as ec2.CfnSecurityGroup
addCfnNagSuppressRules(cfnclusterSG, [
{
id: 'W5',
reason: 'Egress of 0.0.0.0/0 is required'
},
{
id: 'W40',
reason: 'Egress IPProtocol of -1 is required'
},
])
const runTask = new tasks.EcsRunTask(this, 'Run Fargate Task', {
integrationPattern: sfn.IntegrationPattern.RUN_JOB,
cluster,
taskDefinition,
assignPublicIp: true,
containerOverrides: [{
containerDefinition,
environment: [
{ name: 'IMAGE', value: sfn.JsonPath.stringAt('$.repositoryName') },
{ name: 'TAG', value: sfn.JsonPath.stringAt('$.imageTag') },
],
}],
launchTarget: new tasks.EcsFargateLaunchTarget(),
resultPath: '$.result',
securityGroups: [clusterSG]
});
const putSuccessInDDBTask = new tasks.DynamoPutItem(this, 'Log Success in DynamoDB', {
item: {
Image: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$.repositoryName')),
Tag: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$.imageTag')),
Execution: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$$.Execution.Name')),
Status: tasks.DynamoAttributeValue.fromString('Done'),
},
table: imageTable,
returnValues: tasks.DynamoReturnValues.NONE,
resultPath: '$.result'
});
const putFailureInDDBTask = new tasks.DynamoPutItem(this, 'Log Failure in DynamoDB', {
item: {
Image: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$.repositoryName')),
Tag: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$.imageTag')),
Execution: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$$.Execution.Name')),
ErrorMessage: tasks.DynamoAttributeValue.fromString(sfn.JsonPath.stringAt('$.result.Error')),
Status: tasks.DynamoAttributeValue.fromString('Error'),
},
table: imageTable,
returnValues: tasks.DynamoReturnValues.NONE,
resultPath: '$.result'
});
const myKeyAlias = kms.Alias.fromAliasName(this, 'AwsSnsDefaultKey', 'alias/aws/sns');
const topic = new sns.Topic(this,
'EcrReplicationTopic',
{
masterKey: myKeyAlias,
}
);
topic.addSubscription(new subscriptions.EmailSubscription(alarmEmail.valueAsString));
const snsTask = new tasks.SnsPublish(this, 'Publish To SNS', {
topic,
integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE,
message: sfn.TaskInput.fromObject({
error: "Failed to copy image",
execution: sfn.JsonPath.stringAt('$$.Execution.Name'),
image: sfn.JsonPath.stringAt('$.repositoryName'),
tag: sfn.JsonPath.stringAt('$.imageTag'),
})
});
const endState = new sfn.Pass(this, 'EndState');
const map = new sfn.Map(this, 'Map State', {
maxConcurrency: 10,
itemsPath: sfn.JsonPath.stringAt('$.Payload'),
});
const retryParam: sfn.RetryProps = {
backoffRate: 2,
interval: cdk.Duration.seconds(60),
maxAttempts: 3,
}
map.iterator(runTask
.addRetry(retryParam)
.addCatch(putFailureInDDBTask.next(snsTask), { resultPath: '$.result' })
.next(putSuccessInDDBTask));
submitJob.next(map).next(endState)
const logGroup = new logs.LogGroup(this, `DTH-ECR-StepFunction-LogGroup`);
// Create role for Step Machine
const ecrStateMachineRole = new iam.Role(this, `DTH-ECR-ecrStateMachineRole`, {
assumedBy: new iam.ServicePrincipal('states.amazonaws.com')
});
const taskDefArnNoVersion = cdk.Stack.of(this).formatArn({
service: 'ecs',
resource: 'task-definition',
resourceName: taskDefinition.family
})
const ecrStateMachineRolePolicy = new iam.Policy(this, 'ecrStateMachineRolePolicy');
ecrStateMachineRolePolicy.addStatements(
new iam.PolicyStatement({
actions: [
'lambda:InvokeFunction'
],
resources: [
listImagesLambda.functionArn
]
}),
new iam.PolicyStatement({
actions: [
'ecs:RunTask'
],
resources: [
taskDefArnNoVersion
]
}),
new iam.PolicyStatement({
actions: [
"ecs:StopTask",
"ecs:DescribeTasks"
],
resources: [
'*'
]
}),
new iam.PolicyStatement({
actions: [
"iam:PassRole"
],
resources: [
taskDefinition.taskRole.roleArn,
taskDefinition.executionRole!.roleArn
]
}),
new iam.PolicyStatement({
actions: [
"dynamodb:PutItem"
],
resources: [
imageTable.tableArn
]
}),
new iam.PolicyStatement({
actions: [
"sns:Publish"
],
resources: [
topic.topicArn
]
}),
new iam.PolicyStatement({
actions: [
"events:PutTargets",
"events:PutRule",
"events:DescribeRule"
],
resources: [
`arn:${cdk.Aws.PARTITION}:events:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:rule/StepFunctionsGetEventsForECSTaskRule`,
]
}),
new iam.PolicyStatement({
actions: [
'logs:CreateLogDelivery',
'logs:GetLogDelivery',
'logs:UpdateLogDelivery',
'logs:DeleteLogDelivery',
'logs:ListLogDeliveries',
'logs:PutResourcePolicy',
'logs:DescribeResourcePolicies',
'logs:DescribeLogGroups'
],
resources: [
'*'
]
}),
);
ecrStateMachineRolePolicy.node.addDependency(listImagesLambda, taskDefinition, imageTable, topic, logGroup);
ecrStateMachineRolePolicy.attachToRole(ecrStateMachineRole);
const cfnecrStateMachineRolePolicy = ecrStateMachineRolePolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfnecrStateMachineRolePolicy, [
{
id: 'W12',
reason: '[*] Access granted as per documentation: https://docs.aws.amazon.com/step-functions/latest/dg/cw-logs.html'
},
{
id: 'W76',
reason: 'SPCM complexity greater then 25 is appropriate for the logic implemented'
}
])
const ecrStateMachine = new sfn.StateMachine(this, 'ECRReplicationStateMachine', {
stateMachineName: `${cdk.Aws.STACK_NAME}-ECRReplicationSM`,
role: ecrStateMachineRole.withoutPolicyUpdates(),
definition: submitJob,
logs: {
destination: logGroup,
level: sfn.LogLevel.ALL,
},
tracingEnabled: true,
});
const cfnlogGroup = logGroup.node.defaultChild as logs.CfnLogGroup
addCfnNagSuppressRules(cfnlogGroup, [
{
id: 'W84',
reason: 'Log group data is always encrypted in CloudWatch Logs using an AWS Managed KMS Key'
},
])
ecrStateMachine.node.addDependency(containerDefinition, taskDefinition, submitJob, logGroup, ecrStateMachineRole, ecrStateMachineRolePolicy)
const smRuleRole = new iam.Role(this, 'ECRReplicationSMExecRole', {
assumedBy: new iam.ServicePrincipal('events.amazonaws.com'),
})
smRuleRole.addToPolicy(new iam.PolicyStatement({
actions: [
"states:StartExecution",
],
resources: [
ecrStateMachine.stateMachineArn,
]
}))
const ecrStateMachineTarget = new SfnStateMachine(ecrStateMachine, { role: smRuleRole });
const smRule = new Rule(this, 'ECRReplicationScheduleRule', {
schedule: Schedule.rate(cdk.Duration.days(1)),
targets: [ecrStateMachineTarget],
});
smRule.node.addDependency(ecrStateMachine, smRuleRole)
const checkExecutionLambdaPolicy = new iam.Policy(this, 'CheckExecutionLambdaPolicy', {
policyName: `${cdk.Aws.STACK_NAME}CheckExecutionLambdaPolicy`,
statements: [
new iam.PolicyStatement({
actions: [
"states:StartExecution",
"states:ListExecutions",
"states:ListStateMachines",
"states:DescribeExecution",
"states:DescribeStateMachineForExecution",
"states:GetExecutionHistory",
"states:ListActivities",
"states:DescribeStateMachine",
"states:DescribeActivity",
],
resources: [
'*'
]
}),
]
});
const cfncheckExecutionLambdaPolicy = checkExecutionLambdaPolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfncheckExecutionLambdaPolicy, [
{
id: 'W12',
reason: 'This IAM policy need * resource'
},
])
const checkExecutionLambdaRole = new iam.Role(this, 'CheckExecutionFunctionRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
})
const checkExecutionLambda = new lambda.Function(this, 'CheckExecutionFunction', {
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'step-func.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
memorySize: 256,
timeout: cdk.Duration.minutes(15),
// tracing: lambda.Tracing.ACTIVE,
environment: {
STATE_MACHINE_ARN: ecrStateMachine.stateMachineArn
},
role: checkExecutionLambdaRole.withoutPolicyUpdates()
});
checkExecutionLambda.node.addDependency(checkExecutionLambdaRole, checkExecutionLambdaPolicy)
checkExecutionLambdaPolicy.attachToRole(checkExecutionLambda.role!)
ecrStateMachine.grantStartExecution(checkExecutionLambda)
ecrStateMachine.grantRead(checkExecutionLambda)
//Run checkExecutionLambda on Create
const lambdaTrigger = new cr.AwsCustomResource(this, 'StatefunctionTrigger', {
policy: cr.AwsCustomResourcePolicy.fromStatements([new iam.PolicyStatement({
actions: ['lambda:InvokeFunction'],
effect: iam.Effect.ALLOW,
resources: [checkExecutionLambda.functionArn]
})]),
timeout: cdk.Duration.minutes(15),
onCreate: {
service: 'Lambda',
action: 'invoke',
parameters: {
FunctionName: checkExecutionLambda.functionName,
InvocationType: 'Event'
},
physicalResourceId: cr.PhysicalResourceId.of('JobSenderTriggerPhysicalId')
},
onUpdate: {
service: 'Lambda',
action: 'invoke',
parameters: {
FunctionName: checkExecutionLambda.functionName,
InvocationType: 'Event'
},
physicalResourceId: cr.PhysicalResourceId.of('JobSenderTriggerPhysicalId')
}
})
lambdaTrigger.node.addDependency(ecrStateMachine, smRule)
}