in source/constructs/lib/cfn-step-functions.ts [33:460]
constructor(scope: cdk.Construct, id: string, props: CloudFormationStateMachineProps) {
super(scope, id);
const createTaskCfnFn = new lambda.Function(this, 'CreateTaskCfnFn', {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.AssetCode.fromAsset(path.join(__dirname, '../lambda/'), {
exclude: ['api/*', 'layer/*']
}),
handler: 'cdk/cfn-task.createTaskCfn',
environment: {
TASK_TABLE: props.taskTableName
},
layers: [props.lambdaLayer],
memorySize: 512,
timeout: cdk.Duration.seconds(60),
description: 'Data Transfer Hub - Create Task'
})
const cfnCreateTaskCfnFn = createTaskCfnFn.node.defaultChild as lambda.CfnFunction
addCfnNagSuppressRules(cfnCreateTaskCfnFn, [
{
id: 'W58',
reason: 'Lambda function already has permission to write CloudWatch Logs'
}
])
const stopTaskCfnFn = new lambda.Function(this, 'StopTaskCfnFn', {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.AssetCode.fromAsset(path.join(__dirname, '../lambda/'), {
exclude: ['api/*', 'layer/*']
}),
handler: 'cdk/cfn-task.stopTaskCfn',
environment: {
TASK_TABLE: props.taskTableName
},
layers: [props.lambdaLayer],
memorySize: 512,
timeout: cdk.Duration.seconds(60),
description: 'Data Transfer Hub - Stop Task'
})
const cfnStopTaskCfnFn = stopTaskCfnFn.node.defaultChild as lambda.CfnFunction
addCfnNagSuppressRules(cfnStopTaskCfnFn, [
{
id: 'W58',
reason: 'Lambda function already has permission to write CloudWatch Logs'
}
])
const taskFnPolicy = new iam.Policy(this, 'TaskFnPolicy', {
statements: [
new iam.PolicyStatement({
actions: [
"states:CreateStateMachine",
"states:DeleteStateMachine",
"states:DescribeStateMachine",
"states:TagResource",
],
resources: [
`arn:${cdk.Aws.PARTITION}:states:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:activity:DTH*`,
`arn:${cdk.Aws.PARTITION}:states:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:stateMachine:DTH*`,
]
}),
new iam.PolicyStatement({
actions: [
"autoscaling:CreateLaunchConfiguration",
"autoscaling:CreateAutoScalingGroup",
"autoscaling:DeleteAutoScalingGroup",
"autoscaling:DeleteLaunchConfiguration",
"autoscaling:UpdateAutoScalingGroup",
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:EnableMetricsCollection",
"autoscaling:DescribeScalingActivities",
"autoscaling:PutScalingPolicy",
"autoscaling:DeletePolicy",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"SNS:CreateTopic",
"SNS:GetTopicAttributes",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:Unsubscribe",
],
resources: [`arn:${cdk.Aws.PARTITION}:sns:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:DTH*`]
}),
new iam.PolicyStatement({
actions: [
"ssm:GetParameters",
"ssm:PutParameter",
"ssm:AddTagsToResource",
"ssm:DeleteParameter",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"events:PutRule",
"events:RemoveTargets",
"events:DescribeRule",
"events:PutTargets",
"events:DeleteRule",
],
resources: [`arn:${cdk.Aws.PARTITION}:events:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:rule/DTH*`]
}),
new iam.PolicyStatement({
actions: [
"cloudformation:Create*",
"cloudformation:Update*",
"cloudformation:Delete*",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"s3:PutBucketNotification",
"s3:GetBucketNotification",
"s3:GetObject",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"dynamodb:CreateTable",
"dynamodb:DescribeTable",
"dynamodb:DeleteTable",
"dynamodb:UpdateItem",
"dynamodb:DescribeContinuousBackups",
"dynamodb:UpdateContinuousBackups",
],
resources: [
`arn:${cdk.Aws.PARTITION}:dynamodb:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:table/DTH*`,
props.taskTableArn
]
}),
new iam.PolicyStatement({
actions: [
"sqs:SendMessage",
"sqs:CreateQueue",
"sqs:GetQueueAttributes",
"sqs:SetQueueAttributes",
"sqs:DeleteQueue",
],
resources: [`arn:${cdk.Aws.PARTITION}:sqs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:DTH*`]
}),
new iam.PolicyStatement({
actions: [
"ec2:createTags",
"ec2:DescribeImages",
"ec2:DescribeVpcs",
"ec2:DescribeInstances",
"ec2:DescribeSubnets",
"ec2:DescribeVolumes",
"ec2:DescribeTags",
"ec2:CreateSecurityGroup",
"ec2:DeleteSecurityGroup",
"ec2:DescribeSecurityGroups",
"ec2:RevokeSecurityGroupEgress",
"ec2:AuthorizeSecurityGroupEgress",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"ecs:RunTask",
"ecs:ListTasks",
"ecs:RegisterTaskDefinition",
"ecs:DeregisterTaskDefinition",
"ecs:DescribeTaskDefinition",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:DeleteLogStream",
"logs:CreateLogStream",
"logs:PutRetentionPolicy",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:GetLogEvents",
"logs:PutMetricFilter",
"logs:DeleteMetricFilter",
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricStatistics",
"cloudwatch:Describe*",
"cloudwatch:PutMetricData",
"cloudwatch:PutMetricAlarm",
"cloudwatch:GetDashboard",
"cloudwatch:DeleteDashboards",
"cloudwatch:DeleteAlarms",
"cloudwatch:PutDashboard",
"cloudwatch:ListDashboards",
],
resources: [
`*`
]
}),
new iam.PolicyStatement({
actions: [
"iam:CreateInstanceProfile",
"iam:CreateRole",
"iam:PutRolePolicy",
"iam:PassRole",
"iam:AttachRolePolicy",
"iam:AddRoleToInstanceProfile",
"iam:RemoveRoleFromInstanceProfile",
"iam:DeleteInstanceProfile",
"iam:GetRole",
"iam:GetPolicy",
"iam:GetRolePolicy",
"iam:ListRoles",
"iam:ListPolicies",
"iam:ListRolePolicies",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:DetachRolePolicy",
],
resources: [
`arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:instance-profile/DTH*`,
`arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:role/DTH*`,
`arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:policy/DTH*`,
]
}),
new iam.PolicyStatement({
actions: [
"lambda:InvokeFunction",
"lambda:AddPermission",
"lambda:CreateFunction",
"lambda:CreateEventSourceMapping",
"lambda:DeleteEventSourceMapping",
"lambda:PublishLayerVersion",
"lambda:DeleteLayerVersion",
"lambda:DeleteFunction",
"lambda:RemovePermission",
"lambda:UpdateFunctionConfiguration",
"lambda:UpdateFunctionCode",
"lambda:PublishVersion",
"lambda:Get*",
"lambda:List*",
],
resources: [
`*`
]
}),
new iam.PolicyStatement({
actions: [
"kms:CreateKey",
"kms:CreateAlias",
"kms:CreateGrant",
"kms:DeleteAlias",
"kms:DescribeKey",
"kms:DisableKey",
"kms:EnableKey",
"kms:EnableKeyRotation",
"kms:GetKeyRotationStatus",
"kms:GetKeyPolicy",
"kms:GetParametersForImport",
"kms:ImportKeyMaterial",
"kms:PutKeyPolicy",
"kms:TagResource",
"kms:UntagResource",
"kms:UpdateAlias",
],
resources: [
`*`,
]
}),
new iam.PolicyStatement({
actions: [
"ecr:CreateRepository",
"ecr:CompleteLayerUpload",
"ecr:UploadLayerPart",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:GetAuthorizationToken"
],
resources: [`*`]
}),
new iam.PolicyStatement({
actions: [
"iam:CreateServiceLinkedRole",
],
resources: [
`arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling`
]
}),
]
});
createTaskCfnFn.role?.attachInlinePolicy(taskFnPolicy)
stopTaskCfnFn.role?.attachInlinePolicy(taskFnPolicy)
const cfnTaskFnPolicy = taskFnPolicy.node.defaultChild as iam.CfnPolicy
addCfnNagSuppressRules(cfnTaskFnPolicy, [
{
id: 'F4',
reason: 'This policy requires releted actions in order to start/delete other cloudformation stacks of the plugin with many other services'
},
{
id: 'F39',
reason: 'This policy requires releted PassRole actions to unknown resources created by plugin cloudformation stacks'
},
{
id: 'W76',
reason: 'This policy needs to be able to start/delete other complex cloudformation stacks'
},
{
id: 'W12',
reason: 'This policy needs to be able to start/delete other cloudformation stacks of the plugin with unknown resources names'
}
])
const queryTaskCfnFn = new lambda.Function(this, 'QueryTaskCfnFn', {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.AssetCode.fromAsset(path.join(__dirname, '../lambda/'), {
exclude: ['api/*', 'layer/*']
}),
handler: 'cdk/cfn-task.queryTaskCfn',
environment: {
TASK_TABLE: props.taskTableName
},
layers: [props.lambdaLayer],
memorySize: 512,
timeout: cdk.Duration.seconds(60),
description: 'Data Transfer Hub - Query Task'
})
const cfnQueryTaskCfnFn = queryTaskCfnFn.node.defaultChild as lambda.CfnFunction
addCfnNagSuppressRules(cfnQueryTaskCfnFn, [
{
id: 'W58',
reason: 'Lambda function already has permission to write CloudWatch Logs'
}
])
queryTaskCfnFn.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [props.taskTableArn],
actions: [
'dynamodb:Query',
'dynamodb:UpdateItem'
]
}))
queryTaskCfnFn.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [`arn:${cdk.Aws.PARTITION}:cloudformation:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:stack/DTH*`],
actions: [
'cloudformation:DescribeStacks'
]
}))
const startStackTask = new sfnTasks.LambdaInvoke(this, 'Start Stack', {
lambdaFunction: createTaskCfnFn,
outputPath: '$.Payload'
})
const stopStackTask = new sfnTasks.LambdaInvoke(this, 'Stop Stack', {
lambdaFunction: stopTaskCfnFn,
outputPath: '$.Payload'
})
const queryStackStatus = new sfnTasks.LambdaInvoke(this, 'Query Stack Status', {
lambdaFunction: queryTaskCfnFn,
outputPath: '$.Payload'
})
const stackOperationSucceed = new sfn.Succeed(this, 'Stack Ops Succeed')
const stackOperationFailed = new sfn.Fail(this, 'Stack Ops Failed')
const waitFor5Seconds = new sfn.Wait(this, 'Wait for 5 seconds', {
time: sfn.WaitTime.duration(cdk.Duration.seconds(5))
})
const queryStackStatusChoice = new sfn.Choice(this, 'Query Stack Status Choice')
.when(
sfn.Condition.or(
sfn.Condition.stringEquals('$.stackStatus', 'CREATE_COMPLETE'),
sfn.Condition.stringEquals('$.stackStatus', 'UPDATE_COMPLETE'),
sfn.Condition.stringEquals('$.stackStatus', 'DELETE_COMPLETE')
)
, stackOperationSucceed)
.when(
sfn.Condition.or(
sfn.Condition.stringEquals('$.stackStatus', 'CREATE_FAILED'),
sfn.Condition.stringEquals('$.stackStatus', 'DELETE_FAILED'),
sfn.Condition.stringEquals('$.stackStatus', 'UPDATE_ROLLBACK_FAILED')
)
, stackOperationFailed
)
.otherwise(waitFor5Seconds)
const definition = new sfn.Choice(this, 'Stack Action Choice')
.when(
sfn.Condition.stringEquals('$.action', 'START'), startStackTask.next(waitFor5Seconds))
.when(
sfn.Condition.stringEquals('$.action', 'STOP'), stopStackTask.next(waitFor5Seconds))
waitFor5Seconds.next(queryStackStatus).next(queryStackStatusChoice)
const stateMachine = new sfn.StateMachine(this, 'CfnDeploymentStateMachine', {
definition: definition,
timeout: cdk.Duration.minutes(120)
})
new cdk.CfnOutput(this, 'CfnDeploymentStateMachineArn', {
value: stateMachine.stateMachineArn,
description: 'StateMachine Arn',
exportName: 'StateMachineArn'
})
this.stateMachineArn = stateMachine.stateMachineArn
}