Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(event-targets): EcsTask uses invalid task definition arn in policy #30390

Closed
blimmer opened this issue May 30, 2024 · 4 comments · Fixed by #31615 or softwaremill/tapir#4137 · May be fixed by NOUIY/aws-solutions-constructs#135, NOUIY/aws-solutions-constructs#136 or bensullivan2002/photo-website#3
Assignees
Labels
@aws-cdk/aws-events-targets bug This issue is a bug. effort/small Small work item – less than a day of effort p1

Comments

@blimmer
Copy link
Contributor

blimmer commented May 30, 2024

Describe the bug

AWS recently sent this warning:

We are contacting you because we recently identified an issue with 
Amazon Elastic Container Service (Amazon ECS) APIs that require your 
action. When calling the RunTask [1], StartTask [2], CreateService [3], 
CreateTaskSet [4], UpdateService [5] APIs, users can specify a task 
revision number to launch a specific version of that task [6]. We 
identified an issue that resulted in inconsistencies in how the Identity
 and Access Management (IAM) policies are enforced during request 
authorization to the above mentioned APIs. Specifically, resource 
condition keys specifying task-definition families without a revision 
number could potentially be interpreted differently if the task 
definition did not include a revision number when the API was called. As
 a result, the latest version of the task would be selected. We have 
implemented a fix and can confirm the service is operating as expected. 

We identified your account has made requests to one or more of the 
affected ECS APIs. We recommend you review the policies listed in the 
"Affected resources" tab of your AWS Health Dashboard to ensure the 
resource condition keys specifying task-definition families include a 
revision number. To give you time to review and make necessary changes, 
we have added your account to an allow list until October 15, 2024. If 
you wish to be removed from the allow list prior to October 15, 2024, 
you can do so by creating an AWS Support case [7]. If you do not take 
any action by that date, calls to the affected APIs will result in 
AccessDeniedException error messages. 

To correctly enforce IAM policy-based decisions after October 15, 2024, 
you must specify a revision number, or the wildcard (‘*’) for the task 
definition family, on task definition ARNs when used as a resource type.
 

An example of a policy that will correctly ALLOW for all tasks definition revisions is shown below:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Allow",

            "Action": "ecs:RunTask",

            "Resource": "arn:aws:ecs:*:*:task-definition/sleep360:*"

        }

    ]

}

An example of a policy that will correctly DENY for all tasks definition revisions is shown below:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Deny",

            "Action": "ecs:RunTask",

            "Resource": "arn:aws:ecs:*:*:task-definition/sleep360:*"

        }

    ]

}

When you intend to apply the policy for a specific revision of the task 
definition, you must specify the revision in the resource ARN. The 
following is an example of a policy would correctly enforce ALLOW for a 
specific task definition revision:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Allow",

            "Action": "ecs:RunTask",

            "Resource": "arn:aws:ecs:*:*:task-definition/sleep360:7"

        }

    ]

}

An example of a policy would correctly enforce DENY for a specific task definition revision:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Deny",

            "Action": "ecs:RunTask",

            "Resource": "arn:aws:ecs:*:*:task-definition/sleep360:7"

        }

    ]

}

If you have questions or concerns, please contact AWS Support [7].

[1] [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html)

[2] [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_StartTask.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_StartTask.html)

[3] [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html)

[4] [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateTaskSet.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateTaskSet.html)

[5] [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html)

[6] [https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelasticcontainerservice.html#amazonelasticcontainerservice-resources-for-iam-policies](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelasticcontainerservice.html#amazonelasticcontainerservice-resources-for-iam-policies)

[7] [https://aws.amazon.com/support](https://aws.amazon.com/support)

Sincerely,

Amazon Web Services

Of our affected resources, many were policies generated by the EcsTask target:

const policyStatements = [
new iam.PolicyStatement({
actions: ['ecs:RunTask'],
resources: [this.taskDefinition.taskDefinitionArn],
conditions: {
ArnEquals: { 'ecs:cluster': this.cluster.clusterArn },
},
}),
new iam.PolicyStatement({
actions: ['ecs:TagResource'],
resources: [`arn:${this.cluster.stack.partition}:ecs:${this.cluster.env.region}:*:task/${this.cluster.clusterName}/*`],
}),
];

Expected Behavior

The EcsTask construct should generate a valid task definition reference in the generated policy.

Current Behavior

The generated policy includes an invalid reference, like this:

{
  "TaskDefImportEventsRoleDefaultPolicyA6BD21B8": {
   "Type": "AWS::IAM::Policy",
   "Properties": {
    "PolicyDocument": {
     "Statement": [
      {
       "Action": "ecs:RunTask",
       "Condition": {
        "ArnEquals": {
         "ecs:cluster": {
          "Fn::GetAtt": [
           "ClusterEB0386A7",
           "Arn"
          ]
         }
        }
       },
       "Effect": "Allow",
       "Resource": "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask"
      },
      {
       "Action": "ecs:TagResource",
       "Effect": "Allow",
       "Resource": {
        "Fn::Join": [
         "",
         [
          "arn:",
          {
           "Ref": "AWS::Partition"
          },
          ":ecs:",
          {
           "Ref": "AWS::Region"
          },
          ":*:task/",
          {
           "Ref": "ClusterEB0386A7"
          },
          "/*"
         ]
        ]
       }
      },
      {
       "Action": "iam:PassRole",
       "Effect": "Allow",
       "Resource": "arn:aws:iam::123456789101:role/MyTaskRole"
      }
     ],
     "Version": "2012-10-17"
    },
    "PolicyName": "TaskDefImportEventsRoleDefaultPolicyA6BD21B8",
    "Roles": [
     {
      "Ref": "TaskDefImportEventsRole9184C90E"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/TaskDefImport/EventsRole/DefaultPolicy/Resource"
   }
  }
}

Specifically, "Resource": "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask" needs to be "Resource": "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask:*" to comply with the new requirements.

Reproduction Steps

This stack

import { Duration, Stack, type StackProps } from 'aws-cdk-lib';
import { Cluster, FargateTaskDefinition, NetworkMode } from 'aws-cdk-lib/aws-ecs';
import { Rule, Schedule } from 'aws-cdk-lib/aws-events';
import { EcsTask } from 'aws-cdk-lib/aws-events-targets';
import { Role } from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class TestCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const cluster = new Cluster(this, 'Cluster');
    const taskDefinition = FargateTaskDefinition.fromFargateTaskDefinitionAttributes(this, "TaskDefImport", {
      taskDefinitionArn: "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask",
      taskRole: Role.fromRoleArn(this, "RoleImport", "arn:aws:iam::123456789101:role/MyTaskRole"),
      networkMode: NetworkMode.AWS_VPC,
    });
    new Rule(this, "Rule", {
      targets: [new EcsTask({
        cluster,
        taskDefinition
      })],
      schedule: Schedule.rate(Duration.days(1)),
    });
  }
}

Produces

{
 "Resources": {
  "ClusterEB0386A7": {
   "Type": "AWS::ECS::Cluster",
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Resource"
   }
  },
  "ClusterVpcFAA3CEDF": {
   "Type": "AWS::EC2::VPC",
   "Properties": {
    "CidrBlock": "10.0.0.0/16",
    "EnableDnsHostnames": true,
    "EnableDnsSupport": true,
    "InstanceTenancy": "default",
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/Resource"
   }
  },
  "ClusterVpcPublicSubnet1SubnetA9F7E0A5": {
   "Type": "AWS::EC2::Subnet",
   "Properties": {
    "AvailabilityZone": {
     "Fn::Select": [
      0,
      {
       "Fn::GetAZs": ""
      }
     ]
    },
    "CidrBlock": "10.0.0.0/18",
    "MapPublicIpOnLaunch": true,
    "Tags": [
     {
      "Key": "aws-cdk:subnet-name",
      "Value": "Public"
     },
     {
      "Key": "aws-cdk:subnet-type",
      "Value": "Public"
     },
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet1"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/Subnet"
   }
  },
  "ClusterVpcPublicSubnet1RouteTable5594A636": {
   "Type": "AWS::EC2::RouteTable",
   "Properties": {
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet1"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/RouteTable"
   }
  },
  "ClusterVpcPublicSubnet1RouteTableAssociation0FBEF1F4": {
   "Type": "AWS::EC2::SubnetRouteTableAssociation",
   "Properties": {
    "RouteTableId": {
     "Ref": "ClusterVpcPublicSubnet1RouteTable5594A636"
    },
    "SubnetId": {
     "Ref": "ClusterVpcPublicSubnet1SubnetA9F7E0A5"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/RouteTableAssociation"
   }
  },
  "ClusterVpcPublicSubnet1DefaultRoute62DA4B4B": {
   "Type": "AWS::EC2::Route",
   "Properties": {
    "DestinationCidrBlock": "0.0.0.0/0",
    "GatewayId": {
     "Ref": "ClusterVpcIGW1E358A6E"
    },
    "RouteTableId": {
     "Ref": "ClusterVpcPublicSubnet1RouteTable5594A636"
    }
   },
   "DependsOn": [
    "ClusterVpcVPCGW47AC17E9"
   ],
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/DefaultRoute"
   }
  },
  "ClusterVpcPublicSubnet1EIP433C56EE": {
   "Type": "AWS::EC2::EIP",
   "Properties": {
    "Domain": "vpc",
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet1"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/EIP"
   }
  },
  "ClusterVpcPublicSubnet1NATGateway0693C346": {
   "Type": "AWS::EC2::NatGateway",
   "Properties": {
    "AllocationId": {
     "Fn::GetAtt": [
      "ClusterVpcPublicSubnet1EIP433C56EE",
      "AllocationId"
     ]
    },
    "SubnetId": {
     "Ref": "ClusterVpcPublicSubnet1SubnetA9F7E0A5"
    },
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet1"
     }
    ]
   },
   "DependsOn": [
    "ClusterVpcPublicSubnet1DefaultRoute62DA4B4B",
    "ClusterVpcPublicSubnet1RouteTableAssociation0FBEF1F4"
   ],
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet1/NATGateway"
   }
  },
  "ClusterVpcPublicSubnet2Subnet059113C4": {
   "Type": "AWS::EC2::Subnet",
   "Properties": {
    "AvailabilityZone": {
     "Fn::Select": [
      1,
      {
       "Fn::GetAZs": ""
      }
     ]
    },
    "CidrBlock": "10.0.64.0/18",
    "MapPublicIpOnLaunch": true,
    "Tags": [
     {
      "Key": "aws-cdk:subnet-name",
      "Value": "Public"
     },
     {
      "Key": "aws-cdk:subnet-type",
      "Value": "Public"
     },
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet2"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/Subnet"
   }
  },
  "ClusterVpcPublicSubnet2RouteTable7B43F18C": {
   "Type": "AWS::EC2::RouteTable",
   "Properties": {
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet2"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/RouteTable"
   }
  },
  "ClusterVpcPublicSubnet2RouteTableAssociation8446B27D": {
   "Type": "AWS::EC2::SubnetRouteTableAssociation",
   "Properties": {
    "RouteTableId": {
     "Ref": "ClusterVpcPublicSubnet2RouteTable7B43F18C"
    },
    "SubnetId": {
     "Ref": "ClusterVpcPublicSubnet2Subnet059113C4"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/RouteTableAssociation"
   }
  },
  "ClusterVpcPublicSubnet2DefaultRoute97446C8A": {
   "Type": "AWS::EC2::Route",
   "Properties": {
    "DestinationCidrBlock": "0.0.0.0/0",
    "GatewayId": {
     "Ref": "ClusterVpcIGW1E358A6E"
    },
    "RouteTableId": {
     "Ref": "ClusterVpcPublicSubnet2RouteTable7B43F18C"
    }
   },
   "DependsOn": [
    "ClusterVpcVPCGW47AC17E9"
   ],
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/DefaultRoute"
   }
  },
  "ClusterVpcPublicSubnet2EIP203DF3E5": {
   "Type": "AWS::EC2::EIP",
   "Properties": {
    "Domain": "vpc",
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet2"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/EIP"
   }
  },
  "ClusterVpcPublicSubnet2NATGateway00B24686": {
   "Type": "AWS::EC2::NatGateway",
   "Properties": {
    "AllocationId": {
     "Fn::GetAtt": [
      "ClusterVpcPublicSubnet2EIP203DF3E5",
      "AllocationId"
     ]
    },
    "SubnetId": {
     "Ref": "ClusterVpcPublicSubnet2Subnet059113C4"
    },
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PublicSubnet2"
     }
    ]
   },
   "DependsOn": [
    "ClusterVpcPublicSubnet2DefaultRoute97446C8A",
    "ClusterVpcPublicSubnet2RouteTableAssociation8446B27D"
   ],
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PublicSubnet2/NATGateway"
   }
  },
  "ClusterVpcPrivateSubnet1SubnetA4EB481A": {
   "Type": "AWS::EC2::Subnet",
   "Properties": {
    "AvailabilityZone": {
     "Fn::Select": [
      0,
      {
       "Fn::GetAZs": ""
      }
     ]
    },
    "CidrBlock": "10.0.128.0/18",
    "MapPublicIpOnLaunch": false,
    "Tags": [
     {
      "Key": "aws-cdk:subnet-name",
      "Value": "Private"
     },
     {
      "Key": "aws-cdk:subnet-type",
      "Value": "Private"
     },
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PrivateSubnet1"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet1/Subnet"
   }
  },
  "ClusterVpcPrivateSubnet1RouteTable5AAEDA3F": {
   "Type": "AWS::EC2::RouteTable",
   "Properties": {
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PrivateSubnet1"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet1/RouteTable"
   }
  },
  "ClusterVpcPrivateSubnet1RouteTableAssociation9B8A88D9": {
   "Type": "AWS::EC2::SubnetRouteTableAssociation",
   "Properties": {
    "RouteTableId": {
     "Ref": "ClusterVpcPrivateSubnet1RouteTable5AAEDA3F"
    },
    "SubnetId": {
     "Ref": "ClusterVpcPrivateSubnet1SubnetA4EB481A"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet1/RouteTableAssociation"
   }
  },
  "ClusterVpcPrivateSubnet1DefaultRoute3B4D40DD": {
   "Type": "AWS::EC2::Route",
   "Properties": {
    "DestinationCidrBlock": "0.0.0.0/0",
    "NatGatewayId": {
     "Ref": "ClusterVpcPublicSubnet1NATGateway0693C346"
    },
    "RouteTableId": {
     "Ref": "ClusterVpcPrivateSubnet1RouteTable5AAEDA3F"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet1/DefaultRoute"
   }
  },
  "ClusterVpcPrivateSubnet2SubnetBD1ECB6E": {
   "Type": "AWS::EC2::Subnet",
   "Properties": {
    "AvailabilityZone": {
     "Fn::Select": [
      1,
      {
       "Fn::GetAZs": ""
      }
     ]
    },
    "CidrBlock": "10.0.192.0/18",
    "MapPublicIpOnLaunch": false,
    "Tags": [
     {
      "Key": "aws-cdk:subnet-name",
      "Value": "Private"
     },
     {
      "Key": "aws-cdk:subnet-type",
      "Value": "Private"
     },
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PrivateSubnet2"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet2/Subnet"
   }
  },
  "ClusterVpcPrivateSubnet2RouteTable73064A66": {
   "Type": "AWS::EC2::RouteTable",
   "Properties": {
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc/PrivateSubnet2"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet2/RouteTable"
   }
  },
  "ClusterVpcPrivateSubnet2RouteTableAssociationFB21349E": {
   "Type": "AWS::EC2::SubnetRouteTableAssociation",
   "Properties": {
    "RouteTableId": {
     "Ref": "ClusterVpcPrivateSubnet2RouteTable73064A66"
    },
    "SubnetId": {
     "Ref": "ClusterVpcPrivateSubnet2SubnetBD1ECB6E"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet2/RouteTableAssociation"
   }
  },
  "ClusterVpcPrivateSubnet2DefaultRoute011666AF": {
   "Type": "AWS::EC2::Route",
   "Properties": {
    "DestinationCidrBlock": "0.0.0.0/0",
    "NatGatewayId": {
     "Ref": "ClusterVpcPublicSubnet2NATGateway00B24686"
    },
    "RouteTableId": {
     "Ref": "ClusterVpcPrivateSubnet2RouteTable73064A66"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/PrivateSubnet2/DefaultRoute"
   }
  },
  "ClusterVpcIGW1E358A6E": {
   "Type": "AWS::EC2::InternetGateway",
   "Properties": {
    "Tags": [
     {
      "Key": "Name",
      "Value": "TestCdkStack/Cluster/Vpc"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/IGW"
   }
  },
  "ClusterVpcVPCGW47AC17E9": {
   "Type": "AWS::EC2::VPCGatewayAttachment",
   "Properties": {
    "InternetGatewayId": {
     "Ref": "ClusterVpcIGW1E358A6E"
    },
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/VPCGW"
   }
  },
  "ClusterVpcRestrictDefaultSecurityGroupCustomResourceA87DC6B5": {
   "Type": "Custom::VpcRestrictDefaultSG",
   "Properties": {
    "ServiceToken": {
     "Fn::GetAtt": [
      "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E",
      "Arn"
     ]
    },
    "DefaultSecurityGroupId": {
     "Fn::GetAtt": [
      "ClusterVpcFAA3CEDF",
      "DefaultSecurityGroup"
     ]
    },
    "Account": {
     "Ref": "AWS::AccountId"
    }
   },
   "UpdateReplacePolicy": "Delete",
   "DeletionPolicy": "Delete",
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Cluster/Vpc/RestrictDefaultSecurityGroupCustomResource/Default"
   }
  },
  "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0": {
   "Type": "AWS::IAM::Role",
   "Properties": {
    "AssumeRolePolicyDocument": {
     "Version": "2012-10-17",
     "Statement": [
      {
       "Action": "sts:AssumeRole",
       "Effect": "Allow",
       "Principal": {
        "Service": "lambda.amazonaws.com"
       }
      }
     ]
    },
    "ManagedPolicyArns": [
     {
      "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
     }
    ],
    "Policies": [
     {
      "PolicyName": "Inline",
      "PolicyDocument": {
       "Version": "2012-10-17",
       "Statement": [
        {
         "Effect": "Allow",
         "Action": [
          "ec2:AuthorizeSecurityGroupIngress",
          "ec2:AuthorizeSecurityGroupEgress",
          "ec2:RevokeSecurityGroupIngress",
          "ec2:RevokeSecurityGroupEgress"
         ],
         "Resource": [
          {
           "Fn::Join": [
            "",
            [
             "arn:",
             {
              "Ref": "AWS::Partition"
             },
             ":ec2:",
             {
              "Ref": "AWS::Region"
             },
             ":",
             {
              "Ref": "AWS::AccountId"
             },
             ":security-group/",
             {
              "Fn::GetAtt": [
               "ClusterVpcFAA3CEDF",
               "DefaultSecurityGroup"
              ]
             }
            ]
           ]
          }
         ]
        }
       ]
      }
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role"
   }
  },
  "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E": {
   "Type": "AWS::Lambda::Function",
   "Properties": {
    "Code": {
     "S3Bucket": {
      "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
     },
     "S3Key": "ee7de53d64cc9d6248fa6aa550f92358f6c907b5efd6f3298aeab1b5e7ea358a.zip"
    },
    "Timeout": 900,
    "MemorySize": 128,
    "Handler": "__entrypoint__.handler",
    "Role": {
     "Fn::GetAtt": [
      "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0",
      "Arn"
     ]
    },
    "Runtime": "nodejs18.x",
    "Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group"
   },
   "DependsOn": [
    "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0"
   ],
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler",
    "aws:asset:path": "asset.ee7de53d64cc9d6248fa6aa550f92358f6c907b5efd6f3298aeab1b5e7ea358a",
    "aws:asset:property": "Code"
   }
  },
  "TaskDefImportEventsRole9184C90E": {
   "Type": "AWS::IAM::Role",
   "Properties": {
    "AssumeRolePolicyDocument": {
     "Statement": [
      {
       "Action": "sts:AssumeRole",
       "Effect": "Allow",
       "Principal": {
        "Service": "events.amazonaws.com"
       }
      }
     ],
     "Version": "2012-10-17"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/TaskDefImport/EventsRole/Resource"
   }
  },
  "TaskDefImportEventsRoleDefaultPolicyA6BD21B8": {
   "Type": "AWS::IAM::Policy",
   "Properties": {
    "PolicyDocument": {
     "Statement": [
      {
       "Action": "ecs:RunTask",
       "Condition": {
        "ArnEquals": {
         "ecs:cluster": {
          "Fn::GetAtt": [
           "ClusterEB0386A7",
           "Arn"
          ]
         }
        }
       },
       "Effect": "Allow",
       "Resource": "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask"
      },
      {
       "Action": "ecs:TagResource",
       "Effect": "Allow",
       "Resource": {
        "Fn::Join": [
         "",
         [
          "arn:",
          {
           "Ref": "AWS::Partition"
          },
          ":ecs:",
          {
           "Ref": "AWS::Region"
          },
          ":*:task/",
          {
           "Ref": "ClusterEB0386A7"
          },
          "/*"
         ]
        ]
       }
      },
      {
       "Action": "iam:PassRole",
       "Effect": "Allow",
       "Resource": "arn:aws:iam::123456789101:role/MyTaskRole"
      }
     ],
     "Version": "2012-10-17"
    },
    "PolicyName": "TaskDefImportEventsRoleDefaultPolicyA6BD21B8",
    "Roles": [
     {
      "Ref": "TaskDefImportEventsRole9184C90E"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/TaskDefImport/EventsRole/DefaultPolicy/Resource"
   }
  },
  "TaskDefImportSecurityGroup9D869A93": {
   "Type": "AWS::EC2::SecurityGroup",
   "Properties": {
    "GroupDescription": "TestCdkStack/TaskDefImport/SecurityGroup",
    "SecurityGroupEgress": [
     {
      "CidrIp": "0.0.0.0/0",
      "Description": "Allow all outbound traffic by default",
      "IpProtocol": "-1"
     }
    ],
    "VpcId": {
     "Ref": "ClusterVpcFAA3CEDF"
    }
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/TaskDefImport/SecurityGroup/Resource"
   }
  },
  "Rule4C995B7F": {
   "Type": "AWS::Events::Rule",
   "Properties": {
    "ScheduleExpression": "rate(1 day)",
    "State": "ENABLED",
    "Targets": [
     {
      "Arn": {
       "Fn::GetAtt": [
        "ClusterEB0386A7",
        "Arn"
       ]
      },
      "EcsParameters": {
       "LaunchType": "FARGATE",
       "NetworkConfiguration": {
        "AwsVpcConfiguration": {
         "AssignPublicIp": "DISABLED",
         "SecurityGroups": [
          {
           "Fn::GetAtt": [
            "TaskDefImportSecurityGroup9D869A93",
            "GroupId"
           ]
          }
         ],
         "Subnets": [
          {
           "Ref": "ClusterVpcPrivateSubnet1SubnetA4EB481A"
          },
          {
           "Ref": "ClusterVpcPrivateSubnet2SubnetBD1ECB6E"
          }
         ]
        }
       },
       "TaskCount": 1,
       "TaskDefinitionArn": "arn:aws:ecs:us-west-2:123456789101:task-definition/MyTask"
      },
      "Id": "Target0",
      "Input": "{}",
      "RoleArn": {
       "Fn::GetAtt": [
        "TaskDefImportEventsRole9184C90E",
        "Arn"
       ]
      }
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/Rule/Resource"
   }
  },
  "CDKMetadata": {
   "Type": "AWS::CDK::Metadata",
   "Properties": {
    "Analytics": "v2:deflate64:H4sIAAAAAAAA/3WQzW6DQAyEnyX3ZUtoX4CiKsqlQlDlWpnFSZ3AbrT2giLEu1f8KPTS04w/j6yRE71/e9X7HfQcmfoWNVTpoRQwNwU9fw9oWA9ZE1jQq+xsVzsqNIkeTnczwVOeqTxUDZkyVBZlYpsrXBD8gqrBjW8sZXaGQMjZZ3gyH8d8kk+QAwj28FC5pw4Et8NHK+gtPgNLk3VKRcD8tGhFlWiCJ3kcvAv3ucNfMCqCVg+FW/rNmruGzHxwcaPCDq2wHoqwxkKD46gKZBe8QZUFFtdu49n+s8q966hG/w6MKmVGKQUuZC/zd52taXrFqKyrUV/5pUtivY91vLsyUeSDFWpRF4v+At5yBN++AQAA"
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/CDKMetadata/Default"
   },
   "Condition": "CDKMetadataAvailable"
  }
 },
 "Conditions": {
  "CDKMetadataAvailable": {
   "Fn::Or": [
    {
     "Fn::Or": [
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "af-south-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-east-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-northeast-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-northeast-2"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-south-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-southeast-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ap-southeast-2"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "ca-central-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "cn-north-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "cn-northwest-1"
       ]
      }
     ]
    },
    {
     "Fn::Or": [
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-central-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-north-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-south-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-west-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-west-2"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "eu-west-3"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "il-central-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "me-central-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "me-south-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "sa-east-1"
       ]
      }
     ]
    },
    {
     "Fn::Or": [
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "us-east-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "us-east-2"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "us-west-1"
       ]
      },
      {
       "Fn::Equals": [
        {
         "Ref": "AWS::Region"
        },
        "us-west-2"
       ]
      }
     ]
    }
   ]
  }
 },
 "Parameters": {
  "BootstrapVersion": {
   "Type": "AWS::SSM::Parameter::Value<String>",
   "Default": "/cdk-bootstrap/hnb659fds/version",
   "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
  }
 },
 "Rules": {
  "CheckBootstrapVersion": {
   "Assertions": [
    {
     "Assert": {
      "Fn::Not": [
       {
        "Fn::Contains": [
         [
          "1",
          "2",
          "3",
          "4",
          "5"
         ],
         {
          "Ref": "BootstrapVersion"
         }
        ]
       }
      ]
     },
     "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
    }
   ]
  }
 }
}

Which is invalid based on the deprecation notice we received.

Possible Solution

If the task definition contains no revision information, a wildcard should automatically be applied.

Additional Information/Context

This is not an issue if the task definition is not imported. For example:

import { Duration, Stack, type StackProps } from 'aws-cdk-lib';
import { Cluster, FargateTaskDefinition } from 'aws-cdk-lib/aws-ecs';
import { Rule, Schedule } from 'aws-cdk-lib/aws-events';
import { EcsTask } from 'aws-cdk-lib/aws-events-targets';
import { Role } from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class TestCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const cluster = new Cluster(this, 'Cluster');
    const taskDefinition = new FargateTaskDefinition(this, 'TaskDef', {});
    new Rule(this, "Rule", {
      targets: [new EcsTask({
        cluster,
        taskDefinition
      })],
      schedule: Schedule.rate(Duration.days(1)),
    });
  }
}

Produces this snippet:

{
  "TaskDefEventsRoleDefaultPolicyA124E85B": {
   "Type": "AWS::IAM::Policy",
   "Properties": {
    "PolicyDocument": {
     "Statement": [
      {
       "Action": "ecs:RunTask",
       "Condition": {
        "ArnEquals": {
         "ecs:cluster": {
          "Fn::GetAtt": [
           "ClusterEB0386A7",
           "Arn"
          ]
         }
        }
       },
       "Effect": "Allow",
       "Resource": {
        "Ref": "TaskDef54694570"
       }
      },
      {
       "Action": "ecs:TagResource",
       "Effect": "Allow",
       "Resource": {
        "Fn::Join": [
         "",
         [
          "arn:",
          {
           "Ref": "AWS::Partition"
          },
          ":ecs:",
          {
           "Ref": "AWS::Region"
          },
          ":*:task/",
          {
           "Ref": "ClusterEB0386A7"
          },
          "/*"
         ]
        ]
       }
      },
      {
       "Action": "iam:PassRole",
       "Effect": "Allow",
       "Resource": {
        "Fn::GetAtt": [
         "TaskDefTaskRole1EDB4A67",
         "Arn"
        ]
       }
      }
     ],
     "Version": "2012-10-17"
    },
    "PolicyName": "TaskDefEventsRoleDefaultPolicyA124E85B",
    "Roles": [
     {
      "Ref": "TaskDefEventsRoleFB3B67B8"
     }
    ]
   },
   "Metadata": {
    "aws:cdk:path": "TestCdkStack/TaskDef/EventsRole/DefaultPolicy/Resource"
   }
  }
}
"Resource": {
	"Ref": "TaskDef54694570"
}

Will reference the full ARN, including the revision, according to the docs.

Screenshot 2024-05-30 at 10 52 39

CDK CLI Version

2.143.1 (build 29b0d66)

Framework Version

No response

Node.js Version

20

OS

MacOS

Language

TypeScript

Language Version

No response

Other information

See also #30368.

@blimmer blimmer added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels May 30, 2024
@blimmer
Copy link
Contributor Author

blimmer commented May 30, 2024

Here's my exteremely hacky workaround, in case anyone else needs to fix this before it's fixed upstream:

const role = (target as any).role as Role;
const statements = (role as any).defaultPolicy.document.statements as PolicyStatement[];
const withoutBadStatements = statements.filter((s) => {
  const isBadStatement = s.actions.length === 1 && s.actions[0] === "ecs:RunTask";
  return !isBadStatement;
});
(role as any).defaultPolicy.document.statements = withoutBadStatements;

role.addToPrincipalPolicy(
  new PolicyStatement({
    actions: ["ecs:RunTask"],
    resources: [importedTaskDefArn + ":*"], // this is the fix for the bug
    conditions: {
      ArnEquals: {
        "ecs:cluster": ecsCluster.clusterArn,
      },
    },
  })
);

@ashishdhingra ashishdhingra self-assigned this May 30, 2024
@ashishdhingra ashishdhingra added investigating This issue is being investigated and/or work is in progress to resolve the issue. and removed needs-triage This issue or PR still needs to be triaged. labels May 30, 2024
@ashishdhingra
Copy link
Contributor

Appears to be an issue based on below references:

Task Definition ARN in IAM policy resource should include task definition Revision Number.

@ashishdhingra ashishdhingra added p1 effort/small Small work item – less than a day of effort and removed investigating This issue is being investigated and/or work is in progress to resolve the issue. labels May 30, 2024
@ashishdhingra ashishdhingra removed their assignment May 30, 2024
jwoehrle pushed a commit to jwoehrle/aws-cdk that referenced this issue Jun 7, 2024
jwoehrle pushed a commit to jwoehrle/aws-cdk that referenced this issue Jun 7, 2024
@shikha372 shikha372 assigned shikha372 and unassigned shikha372 Aug 30, 2024
@moelasmar moelasmar self-assigned this Aug 30, 2024
@shikha372 shikha372 assigned shikha372 and unassigned moelasmar Aug 30, 2024
samson-keung pushed a commit to samson-keung/aws-cdk that referenced this issue Oct 1, 2024
@mergify mergify bot closed this as completed in #31615 Oct 7, 2024
@mergify mergify bot closed this as completed in 4ada3ea Oct 7, 2024
Copy link

github-actions bot commented Oct 7, 2024

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

1 similar comment
Copy link

github-actions bot commented Oct 7, 2024

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.