26
votes

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?

1

1 Answers

38
votes

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
}