3

I'm trying to attach an IAM roles to EC2 instances (not ECS) so they can pull images from ECR.

Valy Dia
  • 2,781
  • 2
  • 12
  • 32
Ricardo Branco
  • 5,740
  • 1
  • 21
  • 31
  • Have you looked at https://www.terraform.io/docs/providers/aws/r/instance.html#iam_instance_profile. In the `iam_instance_profile`, just put in your IAM role name. – krishna_mee2004 Mar 29 '18 at 17:37
  • Yes. But I had to create the profile in the web console. It would be safer to specify just read-only access to specific repositories. – Ricardo Branco Mar 29 '18 at 17:50
  • Do you want to create the IAM role (profile) through terraform or do you just want to attach it to the EC2 instance? – krishna_mee2004 Mar 29 '18 at 17:51
  • I want to create it through terraform so the instances in the template can use it. – Ricardo Branco Mar 29 '18 at 17:52
  • Create IAM role: https://www.terraform.io/docs/providers/aws/r/iam_role.html. Create inline policy (if you want to setup the policies explicitly): https://www.terraform.io/docs/providers/aws/r/iam_role_policy.html. Attach a managed policy: https://www.terraform.io/docs/providers/aws/r/iam_policy_attachment.html. – krishna_mee2004 Mar 29 '18 at 17:57

3 Answers3

2

Do something like this. Note you may want to limit which ECR repos are accessible.

resource "aws_instance" "test" {
  ...
}

resource "aws_launch_configuration" "ecs_cluster" {
  ...
  iam_instance_profile = "${aws_iam_instance_profile.test.id}"
}

resource "aws_iam_role" "test" {
  name = "test_role"
  assume_role_policy = "..."
}

resource "aws_iam_instance_profile" "test" {
  name = "ec2-instance-profile"
  role = "${aws_iam_role.test.name}"
}

resource "aws_iam_role_policy_attachment" "test" {
  role       = "${aws_iam_role.test.name}"
  policy_arn = "${aws_iam_policy.test.arn}"
}

resource "aws_iam_policy" "test" {
  name        = "ec2-instance-pulls-from-ecr"
  description = "EC2 instance can pull from ECR"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}
Eric M. Johnson
  • 6,657
  • 2
  • 13
  • 23
  • 1
    I think the iam role needs to be created? For example: https://www.terraform.io/docs/providers/aws/r/iam_instance_profile.html. – imdibiji Mar 14 '19 at 02:28
  • Given the wording of the question I was assuming there was already a role created in Terraform. I referenced that as "aws_iam_role.test" in the code above. – Eric M. Johnson Mar 14 '19 at 02:31
1

This is known to work in Terraform v0.11.13

cluster.tf

locals {
  cluster_name = "cluster-${terraform.workspace}"
}

resource "aws_iam_role_policy" "cluster_member" {
  name = "${local.cluster_name}"
  role = "${aws_iam_role.cluster_member.id}"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:UpdateContainerInstancesState",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:Submit*",
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}

resource "aws_iam_role" "cluster_member" {
  name = "${local.cluster_name}"

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

resource "aws_iam_instance_profile" "cluster_member" {
  name = "${local.cluster_name}"
  role = "${aws_iam_role.cluster_member.name}"
}

data "template_file" "cloud_config" {
  template = "${file("${path.module}/templates/user_data.sh")}"
  vars {
    ecs_cluster = "${local.cluster_name}"
  }
}

resource "aws_instance" "cluster_member" {
  # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html
  iam_instance_profile = "${aws_iam_instance_profile.cluster_member.name}"

  user_data = "${data.template_file.cloud_config.rendered}"
}

templates/user_data.sh

#!/bin/bash

# See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html

cat <<'EOF' >> /etc/ecs/ecs.config
ECS_CLUSTER=${ecs_cluster}
EOF
mmell
  • 2,448
  • 1
  • 24
  • 16
1

Answer Given by @Eric M. Johnson is correct, Just for the completeness,

resource "aws_launch_configuration" "ecs_launch_configuration" {
  name                        = "${var.application_name}-${var.stack}"
  image_id                    = var.image_id
  instance_type               = var.instance_type
  iam_instance_profile        = aws_iam_instance_profile.esc_launch_configuration_iam_instance_profile.arn
  security_groups             = split(",",aws_security_group.ecs_launch_configuration_security_group.id)
  associate_public_ip_address = "true"
//  key_name                    = "${var.ecs-key-pair-name}"
  user_data                   = data.template_file.user_data.rendered
}

data "template_file" "user_data" {
  template = file("${path.module}/ec2/user-data.sh")

  vars = {
    ecs_cluster_name = "${var.application_name}-${var.stack}"
  }
}

resource "aws_iam_instance_profile" "esc_launch_configuration_iam_instance_profile" {
  name = "${var.application_name}-${var.stack}"
  role = aws_iam_role.iam_role.name
}

resource "aws_iam_role" "iam_role" {
  name = "${var.application_name}-${var.stack}"
  force_detach_policies = true

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

resource "aws_iam_role_policy_attachment" "iam_role_policy_attachment" {
  role       = aws_iam_role.iam_role.name
  policy_arn = aws_iam_policy.ecs_iam_policy.arn
}


resource "aws_iam_policy" "ecs_iam_policy" {
  name = "${var.application_name}-${var.stack}"
  description = "EC2 instance can pull from ECR"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
          "ec2:DescribeTags",
          "ecs:CreateCluster",
          "ecs:DeregisterContainerInstance",
          "ecs:DiscoverPollEndpoint",
          "ecs:Poll",
          "ecs:RegisterContainerInstance",
          "ecs:StartTelemetrySession",
          "ecs:UpdateContainerInstancesState",
          "ecs:Submit*",
          "ecr:GetAuthorizationToken",
          "ecr:BatchCheckLayerAvailability",
          "ecr:GetDownloadUrlForLayer",
          "ecr:BatchGetImage",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}
Saurav Jha
  • 31
  • 3