From 4c7ab4122bec5fb53050379b2654ce7a8f54db14 Mon Sep 17 00:00:00 2001 From: kazuho cryer-shinozuka Date: Sat, 23 Dec 2023 07:34:42 +0900 Subject: [PATCH] feat(ecs): Implement method in ECS cluster to retrieve task ARN (#28381) This pull request introduces a new method within the Cluster class, designed to retrieve the Amazon Resource Names (ARNs) of tasks that are part of a given ECS cluster. Example of how to get task ARN ```ts declare cluster: Cluster; // arn:aws:ecs:{region}:{regionId}:task/{clusterName}/* const taskArnPattern = cluster.arnForTasks("*"); ``` Closes #26232 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk-lib/aws-ecs/README.md | 18 ++++++++- packages/aws-cdk-lib/aws-ecs/lib/cluster.ts | 15 +++++++ .../aws-cdk-lib/aws-ecs/test/cluster.test.ts | 39 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/README.md b/packages/aws-cdk-lib/aws-ecs/README.md index 399ee801cd348..134101df92cd8 100644 --- a/packages/aws-cdk-lib/aws-ecs/README.md +++ b/packages/aws-cdk-lib/aws-ecs/README.md @@ -186,6 +186,22 @@ const capacityProvider = new ecs.AsgCapacityProvider(this, 'AsgCapacityProvider' cluster.addAsgCapacityProvider(capacityProvider); ``` +The following code retrieve the Amazon Resource Names (ARNs) of tasks that are a part of a specified ECS cluster. +It's useful when you want to grant permissions to a task to access other AWS resources. + +```ts +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +const taskARNs = cluster.arnForTasks('*'); // arn:aws:ecs:::task//* + +// Grant the task permission to access other AWS resources +taskDefinition.addToTaskRolePolicy( + new iam.PolicyStatement({ + actions: ['ecs:UpdateTaskProtection'], + resources: [taskARNs], + }) +) +``` ### Bottlerocket @@ -1600,4 +1616,4 @@ taskDefinition.addContainer('TheContainer', { softLimit: 128, }], }); -``` +``` \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts b/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts index f113c95e24ac7..cf469007614b5 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts @@ -583,6 +583,21 @@ export class Cluster extends Resource implements ICluster { } } + /** + * Returns an ARN that represents all tasks within the cluster that match + * the task pattern specified. To represent all tasks, specify ``"*"``. + * + * @param keyPattern Task id pattern + */ + public arnForTasks(keyPattern: string): string { + return Stack.of(this).formatArn({ + service: 'ecs', + resource: 'task', + resourceName: `${this.clusterName}/${keyPattern}`, + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }); + } + private configureWindowsAutoScalingGroup(autoScalingGroup: autoscaling.AutoScalingGroup, options: AddAutoScalingGroupCapacityOptions = {}) { // clear the cache of the agent autoScalingGroup.addUserData('Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache'); diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index b9dc6b9150447..aae6da1bad290 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -2,6 +2,7 @@ import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { Match, Template } from '../../assertions'; import * as autoscaling from '../../aws-autoscaling'; import * as ec2 from '../../aws-ec2'; +import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; @@ -1084,6 +1085,44 @@ describe('cluster', () => { expect(cluster.defaultCloudMapNamespace!.namespaceName).toBe('foo'); }); + test('arnForTasks returns a task arn from key pattern', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskIdPattern = '*'; + + // WHEN + const policyStatement = new iam.PolicyStatement({ + resources: [cluster.arnForTasks(taskIdPattern)], + actions: ['ecs:RunTask'], + principals: [new iam.ServicePrincipal('ecs.amazonaws.com')], + }); + + // THEN + expect(stack.resolve(policyStatement.toStatementJson())).toEqual({ + Action: 'ecs:RunTask', + Effect: 'Allow', + Principal: { Service: 'ecs.amazonaws.com' }, + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecs:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':task/', + { Ref: 'EcsCluster97242B84' }, + `/${taskIdPattern}`, + ], + ], + }, + }); + }); + /* * TODO:v2.0.0 END OF OBSOLETE BLOCK */