boto3 lambda call to run ECS task requires hardcoding in a revision number?

12k views Asked by At

Long story short, I don't want to have to hardcode in ECS task definition revision numbers for tasks into my lambda source codes. It's essentially toil updating my source code each time I have an updated task definition. In the boto3 documentation for ECS run_task(), it clearly states

taskDefinition (string) -- [REQUIRED]

The family and revision (family:revision ) or full ARN of the task definition to run. If a revision is not specified, the latest ACTIVE revision is used.

However, I am finding that if I define the taskDefinition parameter in client.run_task() with no specific revision number, I get a permission error:

An error occurred (AccessDeniedException) when calling the RunTask operation: User: arn:aws:sts::MY_ACCOUNT_ID:assumed-role/my-lambda-role/trigger-ecs-task is not authorized to perform: ecs:RunTask on resource: arn:aws:ecs:MY_REGION:MY_ACCOUNT_ID:task-definition/an-important-task

If I switch my definition to an-important-task:LATEST or an-important-task:*, I get another error:

...is not authorized to perform: ecs:RunTask on resource: *

This is strange, because it appears contrary to what the documentation states- when I include a revision number, like an-important-task:5, the lambda triggers perfectly. In my lambda function, I simply invoke my ECS task:

def lambda_handler(event, context):
    client = boto3.client('ecs')
    print("Running task.")
    response = client.run_task(
        cluster='my-cluster', 
        launchType='FARGATE',
        taskDefinition='an-important-task',  # <-- notice no revision number
        count=1,
        platformVersion='LATEST',
        networkConfiguration={
            'awsvpcConfiguration': {
                'subnets': [
                    'subnet-1',
                    'subnet-2'
                ],
                'assignPublicIp': 'DISABLED'
            }
        })
    print("Finished invoking task.")

In my Terraform definition, I've attached the necessary policies to my role:

resource "aws_lambda_function" "trigger-ecs-task" {
  function_name = "trigger-ecs-task"
  handler = "my-lambda-function.lambda_handler"
  role = "${aws_iam_role.lambda.arn}"
  runtime = "python3.6"
  # other stuff related to how I store my source code for the lambda
}

My role definition, and attaching the permissions to run ECS tasks:

resource "aws_iam_role" "lambda" {
  name = "my-lambda-ecs-role"
  assume_role_policy = "${data.aws_iam_policy_document.lambda-assume-role.json}"
}

data "aws_iam_policy_document" "lambda-assume-role" {
  statement {
    actions = [
      "sts:AssumeRole"]

    principals {
      type = "Service"
      identifiers = [
        "lambda.amazonaws.com"]
    }
  }
}

resource "aws_iam_policy" "run-ecs-policy" {
  name = "run-ecs-task-policy"
  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ecs:RunTask",
            "Resource": "arn:aws:ecs:MY_REGION:MY_ACCOUNT_ID:task-definition/an-important-task:*"
        },
        {
            "Sid": "Stmt1512361993201",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": [
                "arn:aws:iam::************:role/${data.aws_iam_role.ecs-task-execution-role.name}"
            ]
        }
    ]
}
EOF
}

I attach the policy below:

resource "aws_iam_role_policy_attachment" "service-role-attach" {
  role = "${aws_iam_role.lambda.name}"
  policy_arn = "${aws_iam_policy.run-ecs-policy.arn}"
}

Why is AWS refusing to run my task if I don't specify a specific revision? In my policy definition, I am clearly giving permission to runTask on all revisions of the resource:

arn:aws:ecs:MY_REGION:MY_ACCOUNT_ID:task-definition/an-important-task:*
1

There are 1 answers

0
Imran On

I was able to replicate your behavior and resolved the issue with following Resource in IAM Policy.

{
    "Sid": "VisualEditor1",
    "Effect": "Allow",
    "Action": "ecs:RunTask",
    "Resource": "arn:aws:ecs:MY_REGION:MY_ACCOUNT_ID:task-definition/an-important-task"
}

If you are planning to provide with revision then the resource should have :* in it or it has to exactly exactly match with taskDefinition.

Let me know how it goes at your end!!.