I'd like to create and deploy a cluster using terraform ecs_service, but am unable to do so. My terraform applys always fail around IAM roles, which I don't clearly understand. Specifically, the error message is: 
InvalidParametersException: Unable to assume role and validate the specified targetGroupArn. Please verify that the ECS service role being passed has the proper permissions.
And I have found that:
iam_role specified in ecs_service, ECS complains that I need to use a service-linked role.iam_role commented in ecs_service, ECS complains that the assumed role cannot validate the targetGroupArn.My terraform spans a bunch of files. I pulled what feels like the relevant portions out below. Though I have seen a few similar problems posted, none have provided an actionable solution that solves the dilemma above, for me.
## ALB
resource "aws_alb" "frankly_internal_alb" {
    name = "frankly-internal-alb"
    internal = false
    security_groups = ["${aws_security_group.frankly_internal_alb_sg.id}"]
    subnets = ["${aws_subnet.frankly_public_subnet_a.id}", "${aws_subnet.frankly_public_subnet_b.id}"]
}
resource "aws_alb_listener" "frankly_alb_listener" {
    load_balancer_arn = "${aws_alb.frankly_internal_alb.arn}"
    port = "8080"
    protocol = "HTTP"
    default_action {
        target_group_arn = "${aws_alb_target_group.frankly_internal_target_group.arn}"
        type = "forward"
    }
}
## Target Group
resource "aws_alb_target_group" "frankly_internal_target_group" {
    name = "internal-target-group"
    port = 8080
    protocol = "HTTP"
    vpc_id = "${aws_vpc.frankly_vpc.id}"
    health_check {
        healthy_threshold = 5
        unhealthy_threshold = 2
        timeout = 5
    }
}
## IAM
resource "aws_iam_role" "frankly_ec2_role" {
  name               = "franklyec2role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}
resource "aws_iam_role" "frankly_ecs_role" {
  name = "frankly_ecs_role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ecs.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}
# aggresively add permissions...
resource "aws_iam_policy" "frankly_ecs_policy" {
  name        = "frankly_ecs_policy"
  description = "A test policy"
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:*",
        "ecs:*",
        "ecr:*",
        "autoscaling:*",
        "elasticloadbalancing:*",
        "application-autoscaling:*",
        "logs:*",
        "tag:*",
        "resource-groups:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}
resource "aws_iam_role_policy_attachment" "frankly_ecs_attach" {
  role       = "${aws_iam_role.frankly_ecs_role.name}"
  policy_arn = "${aws_iam_policy.frankly_ecs_policy.arn}"
}
## ECS
resource "aws_ecs_cluster" "frankly_ec2" {
    name = "frankly_ec2_cluster"
}
resource "aws_ecs_task_definition" "frankly_ecs_task" {
  family                = "service"
  container_definitions = "${file("terraform/task-definitions/search.json")}"
  volume {
    name      = "service-storage"
    docker_volume_configuration {
      scope         = "shared"
      autoprovision = true
    }
  }
  placement_constraints {
    type       = "memberOf"
    expression = "attribute:ecs.availability-zone in [us-east-1]"
  }
}
resource "aws_ecs_service" "frankly_ecs_service" {
  name            = "frankly_ecs_service"
  cluster         = "${aws_ecs_cluster.frankly_ec2.id}"
  task_definition = "${aws_ecs_task_definition.frankly_ecs_task.arn}"
  desired_count   = 2
  iam_role        = "${aws_iam_role.frankly_ecs_role.arn}"
  depends_on      = ["aws_iam_role.frankly_ecs_role", "aws_alb.frankly_internal_alb", "aws_alb_target_group.frankly_internal_target_group"]
  # network_configuration = {
  #   subnets = ["${aws_subnet.frankly_private_subnet_a.id}", "${aws_subnet.frankly_private_subnet_b}"]
  #   security_groups = ["${aws_security_group.frankly_internal_alb_sg}", "${aws_security_group.frankly_service_sg}"]
  #   # assign_public_ip = true
  # }
  ordered_placement_strategy {
    type  = "binpack"
    field = "cpu"
  }
  load_balancer {
    target_group_arn = "${aws_alb_target_group.frankly_internal_target_group.arn}"
    container_name   = "search-svc"
    container_port   = 8080
  }
  placement_constraints {
    type       = "memberOf"
    expression = "attribute:ecs.availability-zone in [us-east-1]"
  }
}
Returns a set of temporary security credentials that you can use to access AWS resources that you might not normally have access to. These temporary credentials consist of an access key ID, a secret access key, and a security token.
If you receive an error that you're not authorized to perform the iam:PassRole action, your policies must be updated to allow you to pass a role to Resource Groups. Some AWS services allow you to pass an existing role to that service instead of creating a new service role or service-linked role.
AWS differentiates between a task execution role, which is a general role that grants permissions to start the containers defined in a task, and a task role that grants permissions to the actual application once the container is started.
I was seeing an identical error message and I was doing something else wrong:
I had specified the loadbalancer's ARN and not the loadbalancer's target_group ARN.
For me, the problem was that I forgot to attach the right policy to the service role. Attaching this AWS-managed policy helped: arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With