Search code examples
amazon-web-servicesterraformamazon-ecsterraform-provider-awscloudposse

EC2 instance created using terraform with autoscaling group not added to ECS cluster


TL;DR: Does my EC2 instance need an IAM role to be added to my ECS cluster? If so, how do I set that?


I have an EC2 instance created using an autoscaling group. (ASG definition here.) I also have an ECS cluster, which is set on the spawned instances via user_data. I've confirmed that /etc/ecs/ecs.config on the running instance looks correct:

ECS_CLUSTER=my_cluster

However, the instance never appears in the cluster, so the service task doesn't run. There are tons of questions on SO about this, and I've been through them all. The instances are in a public subnet and have access to the internet. The error in ecs-agent.log is:

Error getting ECS instance credentials from default chain: NoCredentialProviders: no valid providers in chain.

So I am guessing that the problem is that the instance has no IAM role associated with it. But I confess that I am a bit confused about all the various "roles" and "services" involved. Does this look like a problem?

enter image description here

If that's it, where do I set this? I'm using Cloud Posse modules. The docs say I shouldn't set a service_role_arn on a service task if I'm using "awsvpc" as the networking mode, but I am not sure whether I should be using a different mode for this setup (multiple containers running as tasks on a single EC2 instance). Also, there are several other roles I can configure here? The ECS service task looks like this:

module "ecs_alb_service_task" {
  source = "cloudposse/ecs-alb-service-task/aws"
  # Cloud Posse recommends pinning every module to a specific version
  version = "0.62.0"

  container_definition_json = jsonencode([for k, def in module.flask_container_def : def.json_map_object])

  name               = "myapp-web"
  security_group_ids = [module.sg.id]
  ecs_cluster_arn    = aws_ecs_cluster.default.arn
  task_exec_role_arn = [aws_iam_role.ec2_task_execution_role.arn]

  launch_type                = "EC2"
  alb_security_group         = module.sg.name
  vpc_id                     = module.vpc.vpc_id
  subnet_ids                 = module.subnets.public_subnet_ids
  network_mode               = "awsvpc"
  desired_count              = 1
  task_memory                = (512 * 3)
  task_cpu                   = 1024
  deployment_controller_type = "ECS"
  enable_all_egress_rule     = false

  health_check_grace_period_seconds  = 10
  deployment_minimum_healthy_percent = 50
  deployment_maximum_percent         = 200

  ecs_load_balancers = [{
    container_name   = "web"
    container_port   = 80
    elb_name         = null
    target_group_arn = module.alb.default_target_group_arn
  }]
}

And here's the policy for the ec2_task_execution_role:

data "aws_iam_policy_document" "ec2_task_execution_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["ecs-tasks.amazonaws.com"]
    }
  }
}

Update: Here is the rest of the declaration of the task execution role:

resource "aws_iam_role" "ec2_task_execution_role" {
  name               = "${var.project_name}_ec2_task_execution_role"
  assume_role_policy = data.aws_iam_policy_document.ec2_task_execution_role.json

  tags = {
    Name    = "${var.project_name}_ec2_task_execution_role"
    Project = var.project_name
  }
}

resource "aws_iam_role_policy_attachment" "ec2_task_execution_role" {
  role       = aws_iam_role.ec2_task_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}


# Create a policy for the EC2 role to use Session Manager
resource "aws_iam_role_policy" "ec2_role_policy" {
  name = "${var.project_name}_ec2_role_policy"
  role = aws_iam_role.ec2_task_execution_role.id
  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : [
          "ssm:DescribeParameters",
          "ssm:GetParametersByPath",
          "ssm:GetParameters",
          "ssm:GetParameter"
        ],
        "Resource" : "*"
      }
    ]
  })
}

Update 2: The EC2 instances are created by the Auto-Scaling Group, see here for my code. The ECS cluster is just this:


# Create the ECS cluster
resource "aws_ecs_cluster" "default" {
  name = "${var.project_name}_cluster"
  tags = {
    Name    = "${var.project_name}_cluster"
    Project = var.project_name
  }
}

I was expecting there to be something like instance_role in the ec2-autoscaling-group module, but there isn't.


Solution

  • You need to set the EC2 instance profile (IAM instance role) via the iam_instance_profile_name setting in the module "autoscale_group".