36

I'm using Terraform to create a few services in AWS. One of those services is an ECS task definition. I followed the docs and I keep getting the following error:

aws_ecs_task_definition.github-backup: ClientException: Fargate requires task definition to have execution role ARN to support ECR images.
status code: 400, request id: 84df70ec-94b4-11e8-b116-97f92c6f483f

First of all the task_role_arn is optional and I can see that a new role was created. I also tried creating a role myself with the permissions required by task definition.

Here's what I have:

Task Definition:

resource "aws_ecs_task_definition" "github-backup" {
  family                   = "${var.task_name}"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "${var.fargate_cpu}"
  memory                   = "${var.fargate_memory}"
  task_role_arn            = "${aws_iam_role.github-role.arn}"

  container_definitions = <<DEFINITION
[
    {
        "cpu": ${var.fargate_cpu},
        "image": "${var.image}",
        "memory": ${var.fargate_memory},
        "name": "github-backup",
        "networkMode": "awsvpc"
    }
]
DEFINITION
}

IAM policy:

resource "aws_iam_policy" "access_policy" {
  name = "github_policy"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Sid": "Stmt1532966429082",
        "Action": [
        "s3:PutObject",
        "s3:PutObjectTagging",
        "s3:PutObjectVersionTagging"
        ],
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::zego-github-backup11"
    },
    {
        "Sid": "Stmt1532967608746",
        "Action": "lambda:*",
        "Effect": "Allow",
        "Resource": "*"
    },
    {
        "Effect": "Allow",
        "Action": [
            "ecr:GetAuthorizationToken",
            "ecr:BatchCheckLayerAvailability",
            "ecr:GetDownloadUrlForLayer",
            "ecr:BatchGetImage",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
EOF
}

IAM role:

resource "aws_iam_role" "github-role" {
  name = "github-backup"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Principal": {
            "Service": [
                "s3.amazonaws.com",
                "lambda.amazonaws.com",
                "ecs.amazonaws.com"
            ]
            },
            "Effect": "Allow",
            "Sid": ""
        }
    ]
}
EOF
}

IAM policy attachment:

resource "aws_iam_role_policy_attachment" "test-attach" {
    role       = "${aws_iam_role.github-role.name}"
    policy_arn = "${aws_iam_policy.access_policy.arn}"
}

Terraform plan doesn't show me any error. Only when running Terraform apply do I get this error. I am providing a role with required permissions to task definition and I still get this. What is wrong with this?

ydaetskcoR
  • 53,225
  • 8
  • 158
  • 177
davidb
  • 1,503
  • 4
  • 30
  • 49

1 Answers1

50

As mentioned in the AWS ECS User Guide Fargate tasks require the execution role to be specified as part of the task definition.

EC2 launch type tasks don't require this because the EC2 instances themselves should have an IAM role that allows them to pull the container image and optionally push logs to Cloudwatch.

Because this is optional for EC2 launch types then Terraform needs to make this optional otherwise it breaks those. Strictly speaking Terraform doesn't have a way to do cross field validation at plan time so it's unable to tell you in the plan that because you have a Fargate launch type task then you need to specify the execution_role_arn. There are workarounds for this using the CustomizeDiff in the provider source but it's hacky as all hell and only used in a couple of places right now.

Note that the execution role is what is needed to launch the task, not the role that the task has that allows the task to do things.

So you should remove the ECS related permissions from your IAM policy as the task should not be interacting with S3 at all. Instead just add a role with the appropriate permissions as the execution role.

To use the AWS managed ECS task execution role you would do something like this:

data "aws_iam_role" "ecs_task_execution_role" {
  name = "ecsTaskExecutionRole"
}

resource "aws_ecs_task_definition" "github-backup" {
  family                   = "${var.task_name}"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "${var.fargate_cpu}"
  memory                   = "${var.fargate_memory}"
  task_role_arn            = "${aws_iam_role.github-role.arn}"
  execution_role_arn       = "${data.aws_iam_role.ecs_task_execution_role.arn}"

  container_definitions = <<DEFINITION
  [
    {
      "cpu": ${var.fargate_cpu},
      "image": "${var.image}",
      "memory": ${var.fargate_memory},
      "name": "github-backup",
      "networkMode": "awsvpc"
    }
  ]
  DEFINITION
}
ydaetskcoR
  • 53,225
  • 8
  • 158
  • 177
  • If you look at my post you can see that I'm specifying `execution_role_arn` in task definition. Also, thanks for formatting. – davidb Jul 31 '18 at 12:39
  • Your task definition in the question doesn't include the `execution_role_arn`. Did you miss adding it? I've edited my answer to show exactly how it should be used and to explain the difference between `execution_role_arn` and `task_role_arn`. – ydaetskcoR Jul 31 '18 at 13:15
  • 1
    Ok, I'm a bit embarrassed now. The issue was caused because I kept misreading execution_role_arn and task_role_arn and thought them to be the same. I changed task_role to execution_role_arn and it's working fine now. Thank you for helping me in noticing this. – davidb Jul 31 '18 at 13:42
  • 2
    These are two separate things. `execution_role_arn` is what's required to launch the task by Fargate and `task_role_arn` is the role the ECS task should be given so that the application can interact with AWS services such as S3. – ydaetskcoR Jul 31 '18 at 13:44