EKS Pod IAM Role using ServiceAccounts

In this tutorial, I will show how to configure EKS Pod to use IAM role through ServiceAccount. In EKS there are many ways to give pod access to AWS resources, from using hard-coded credentials, configuring tools like kiam or kube2iam. However, these tools lack the development and support of AWS. This is why in 2019 AWS announced IAM roles for service accounts for EKS. I won’t go through in details as what is service accounts but I will show you to how to assign IAM role to Pods in EKS via service account. For the cluster setup, I have used terraform-aws-eks module.

Requirements

  1. EKS Kubernetes version at-least 1.14
  2. OpenID connect provider for EKS to be enabled.

Steps

1. Enable OpenID Connect provider

If you have created the EKS cluster via the Terraform module. You just have to set the flag “enable_irsa” to true

module "my-cluster" {
  source          = "terraform-aws-modules/eks/aws"
  enable_irsa     = true
}

This will create an OpenID connect provider linking to your EKS cluster.

2. Create an IAM role with the below assume role policy document

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:<namespace>:<service-account-name>"
        }
      }
    }
  ]
}

For example it would be like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::586162624261:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/E120F2147649A6755C857F1191E9828A"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.eu-west-2.amazonaws.com/id/E120F2147649A6755C857F1191E9828A:sub": "system:serviceaccount:default:my-service"
        }
      }
    }
  ]
}

The OIDC Provider arn can be obtained via the module output. module.my-cluster.oidc_provider_arn

The service account name is the service name which you will create in k8.

In Terraform , if you have used the module you would need to trim “https://” from the output for the condition.

Attach an IAM policy. In this example will just assign S3 Read policy AmazonS3ReadOnlyAccess to it.

3. Create a ServiceAccount in K8

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<IAM_ROLE_NAME>

Make sure you apply the service account to your K8 cluster.

4. Declare the service account in your Pod definition.

apiVersion: batch/v1
kind: Job
metadata:
  name: s3-iam-list
spec:
  template:
    spec:
      serviceAccountName: my-service
      containers:
      - name: eks-iam-test
        image: amazon/aws-cli:latest
        args: ["s3", "ls"]
      restartPolicy: Never

Note, the service account name should match the name in our service account declared earlier.

You can check whether it has worked or not, by viewing the logs.

kubectl logs s3-iam-list

How to hardened the EC2 Node?

When you launch a pod on a node, it has access to all the IAM permission assigned to the EKS node. AWS meta service provides these credentials to any process running on the node. This is not great, as it is difficult to assign the concept of least privilege. Imagine, running 200 pods on the node and all of them have access to the IAM role.

When you assign a service account for a pod, it will have access to both the service account IAM role and the node role. This brings risks, as we just want to have access to the service account role.

To strengthen it and deny pods accessing the IAM role, we would block requests being sent to 169.254.169.254.  This can be easily achieved by blocking requests being sent to that address using iptables.

iptables -A OUTPUT -d 169.254.169.254 -j DROP

Make sure, the pods currently running on the nodes have service account integrated.