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
- Note the
$cluster_name
and$region
of the EKS cluster you're configuring. - 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
- 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.
- Create an AWS policy from
prodvana-ecs-access.json
. You can do this in the AWS console, or with theaws
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",
...
}
}
- 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
- 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 thedefault
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
- 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 thisaws
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"
}
}
}
]
}
Updated 9 months ago