GuidesAPI Reference
Log In
Guides

Configuring IAM in EKS for ECS Deployment

Requirements

  • An EKS Cluster created with this guide: AWS: Configuring an EKS Cluster
  • Access to the EKS Cluster above
  • Follow this guide with an AWS IAM User that has AdministatorAccess
  • eksctl installed in an environment where you have the aws cli tool installed and authenticated

Configuration

  1. Note the $cluster_name and $region of the EKS cluster you're configuring.
  2. First we will add the EKS Cluster's OIDC endpoint as an IAM Identity Provider, this lets IAM manage identities within the cluster:
eksctl utils associate-iam-oidc-provider --cluster $cluster_name -region $region --approve
  1. Create a file named prodvana-ecs-access.json with the following IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ecs:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "ecs:DescribeTaskDefinition",
            "Resource": "*"
        },
        {
            "Action": "iam:PassRole",
            "Effect": "Allow",
            "Resource": [
                "*"
            ],
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": "ecs-tasks.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "tag:getResources"
            ],
            "Resource": "*"
        }
    ]
}

📘

If you would like to scope the IAM policy to only grant access to one ECS cluster, use the policy described here.

  1. Create an AWS policy from prodvana-ecs-access.json. You can do this in the AWS console, or with the aws cli tool:
aws iam create-policy \
    --policy-name prodvana-ecs-access \
    --policy-document file://prodvana-ecs-access.json

This will print out the policy's ARN, make a note of this for the next step.

{
    "Policy": {
        "PolicyName": "prodvana-ecs-access",
        "Arn": "arn:aws:iam::<account_id>:policy/prodvana-ecs-access",
          ...
    }
}
  1. Now let's create a namespace in the EKS cluster where Prodvana will run ECS management tasks. You can choose your own name for this, but make sure to keep a note of it. We'll need it later in this guide, and you'll need it when adding your ECS Runtime to Prodvana.

Run the following kubectl command to create the namespace:

kubectl create namespace prodvana-jobs
  1. Kubernetes automatically creates a default service account in every namespace. We can now create an IAM role with the policy attached, and associate it with the default Service Account in the namespace you just created.
    eksctl has a command that will do all these steps for us (make sure to replace $cluster_name, $region, $prodvana_jobs_namespace, and $prodvana_ecs_access_arn):
eksctl create iamserviceaccount \
    --name default \
    --namespace $prodvana_jobs_namespace \
    --cluster $cluster_name \
    --region $region \
    --role-name prodvana-ecs-access-role \
    --attach-policy-arn $prodvana_ecs_access_arn \
    --approve \
    --override-existing-serviceaccounts
  1. Now we're done! To validate that the trust relationship is established, we can check the role and the service account.
    To check the IAM role side, run this aws command:
aws iam get-role \
    --role-name prodvana-ecs-access-role \
    --query Role.AssumeRolePolicyDocument

The output will look like the json below. Make sure you see system:serviceaccount:<$prodvana_jobs_namespace>:default part in the StringEquals block:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:<ecs_runtime_namespace>:default",
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
                }
            }
        }
    ]
}

To check the Service Account run this kubectl command:

kubectl describe serviceaccount default -n $prodvana_jobs_namespace

Check that you see the eks.amazonaws.com/role-arn Annotation:

Name:                default
Namespace:           <$prodvana_jobs_namespace>
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/prodvana-ecs-access-role
[...]

IAM Policies

Restrict to one ECS Cluster

If you would like to restrict the IAM policy to only give Prodvana permission to manage one of your ECS clusters, use the following policy. Make sure to replace <$region> <$account_id>, and <$ecs_cluster_name>:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:PutAttributes",
                "ecs:UpdateCluster",
                "ecs:ListAttributes",
                "ecs:ExecuteCommand",
                "ecs:UpdateContainerInstancesState",
                "ecs:UpdateTaskProtection",
                "ecs:StartTask",
                "ecs:RegisterContainerInstance",
                "ecs:DeleteAttributes",
                "ecs:DescribeTaskSets",
                "ecs:SubmitAttachmentStateChanges",
                "ecs:Poll",
                "ecs:UpdateService",
                "ecs:DescribeCapacityProviders",
                "ecs:CreateService",
                "ecs:RunTask",
                "ecs:ListTasks",
                "ecs:StopTask",
                "ecs:DescribeServices",
                "ecs:SubmitContainerStateChange",
                "ecs:DescribeContainerInstances",
                "ecs:DeregisterContainerInstance",
                "ecs:DeleteTaskDefinitions",
                "ecs:DescribeTasks",
                "ecs:UntagResource",
                "ecs:UpdateTaskSet",
                "ecs:SubmitTaskStateChange",
                "ecs:GetTaskProtection",
                "ecs:UpdateClusterSettings",
                "ecs:UpdateCapacityProvider",
                "ecs:DeleteService",
                "ecs:DeleteTaskSet",
                "ecs:DescribeClusters",
                "ecs:ListTagsForResource",
                "ecs:StartTelemetrySession",
                "ecs:UpdateContainerAgent",
                "ecs:ListContainerInstances",
                "ecs:UpdateServicePrimaryTaskSet"
            ],
            "Resource": [
                "arn:aws:ecs:<$region>:<$account_id>:task-set/<$ecs_cluster_name>/*/*",
                "arn:aws:ecs:<$region>:<$account_id>:task/<$ecs_cluster_name>/*",
                "arn:aws:ecs:<$region>:<$account_id>:task-definition/*:*",
                "arn:aws:ecs:<$region>:<$account_id>:capacity-provider/*",
                "arn:aws:ecs:<$region>:<$account_id>:cluster/<$ecs_cluster_name>",
                "arn:aws:ecs:<$region>:<$account_id>:service/<$ecs_cluster_name>/*",
                "arn:aws:ecs:<$region>:<$account_id>:container-instance/<$ecs_cluster_name>/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecs:CreateTaskSet",
                "ecs:ListServices"
            ],
            "Resource": "*",
            "Condition": {
                "ArnEquals": {
                    "ecs:cluster": "arn:aws:ecs:<$region>:<$account_id>:cluster/<$ecs_cluster_name>"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecs:TagResource",
                "ecs:ListServicesByNamespace",
                "ecs:DiscoverPollEndpoint",
                "tag:GetResources",
                "ecs:ListAccountSettings",
                "ecs:ListTaskDefinitionFamilies",
                "ecs:ListClusters",
                "ecs:DescribeTaskDefinition",
                "ecs:DeregisterTaskDefinition",
                "ecs:RegisterTaskDefinition",
                "ecs:ListTaskDefinitions"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": "ecs-tasks.amazonaws.com"
                }
            }
        }
    ]
}