In the last article, I covered in brief, the solutions for the problem of authenticating into AWS from K8s workloads. This is the first detailed article (and the video) I promised I’ll follow up that with, going into to details on EKS Pod Identities. I’m hoping to make this the most detailed, most in-depth video on the topic, but this article would probably have less details, so I highly recommend watching the video. It also has a full demo on how to create an EKS cluster for Pod Identities.

Introduction

EKS Pod Identities are only usable in fully fledged EKS clusters, backed by EC2 compute. They are easy to setup, and easy to use, and is the recommended way to get short term credentials into K8s workloads.

You just,

  1. Create the IAM Role to use
  2. Create the K8s Service Account to map to the Role
  3. Map the Serivce Account to IAM Role in AWS
  4. Start using the Service Account for Pods

EKS takes care of providing proper credentials by doing everything in between the Pod and AWS.

How do Pod Identities Work?

Most details here are a bit hard to put together in a meaningful manner as a blog post. The video format works better here to explain details jumping between the demo and the architecture diagram.

If the details here are not that clear, make sure to check my video out. I go into more details than the blog post in the video.

The architecture of how Pod Identities work behind the scenes is a bit complex, compared to how easy it is to get it working as an end user. AWS does a pretty good job of hiding this complexity, but it is still interesting explore, how mostly standard approaches are taken to implement such an elegant UX (DX?) in this area.

I found most of these details by going through the documentation, the code for these components that are open source, and then some details from github issues that talk about a few undocumented scenarios.

There are several moving parts involved in Pod Identities.

EKS Pod Identity Addon

When you create an EKS cluster, you can add several addons to it to enable different types of functionality. EKS Pod Identity Addon is one of these, that in the background adds a Daemonset to the cluster to run an Agent, called the EKS Pod Identity Agent.

The addon also configures the EKS Pod Identity Webhook to configure pods in a specific way.

AWS IAM Roles

IAM Role to use for the specific workload needs to be created with the same best practices that you would use for any other scenario, Principle of Least Privilege, no Confused Deputies, etc.

Additionally, it should allow EKS to assume to role, or more specifically, the principal pods.eks.amazonaws.com to assume to it. This would be the principal EKS uses when a Pod is created to give it the temporary credentials.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "pods.eks.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}

K8s Service Accounts and Mapping to IAM Role

Service Accounts are going to be used to map a Role to a given Pod. Essentially, a Service Account is mapped to the above IAM Role, which tells EKS to use the specific Role to generate temporary credentials.

❯ kubectl create sa pod-identity-test

❯ aws eks create-pod-identity-association --cluster-name <cluster-name>
--service-account pod-identity-test --namespace default --role-arn <role-arn>

AWS SDK Crdentials Lookup Chain

The AWS SDK, when trying to make an authenticated call to AWS, will try to locate credentials from a list of sources. This is called the credentials provider chain and contains source like the credentials file, environment variables, and Instance Metadata Service (IMDSv2). The provider of most interest in EKS Pod Identities is called the Container Credentials Provider, which is basically a way to get credentials from an external credentials server.

The SDK will source details for these different providers through different environment variables. For Container Credentials provider, the following two environment variables should be found.

spec:
  containers:
  - ...
    env:
    - name: AWS_CONTAINER_CREDENTIALS_FULL_URI
      value: https://169.254.170.23/v1/credentials
    - name: AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
      value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
    image: amazon/aws-cli:latest
    imagePullPolicy: Always
    name: pod1
    ...

The values I’ve used above are the default values you would see in EKS Pod Identities scenario. There’s a process that runs on the link local address 169.254.170.23 on every Node in the cluster, and the token to provide to it (and all the way through to AWS through it) is in the Service Account token in /var/run/secrets/eks.amazonaws.com/serviceaccount/token.

So these environment variables should be set for every Pod that needs temporary credentials through EKS Pod Identities. This can be done manually, but you have better things to worry about. There should be a component that,

  1. Mounts the Service Account token
  2. Set these environment variables during Pod creation.

EKS Pod Identity Webhook

This is a K8s Mutating Webhook implementation that gets invoked when a new Pod is scheduled to be created. A mutating webhook mutates the Pod definition, as the name suggests, and in this case, the Pod Identity Webhook mutates the Pod definition so that a couple of environment variables and the Service Account token projection are added to it.

The Webhook knows the list Service Accounts to do these changes, by looking at a configuration file it watches constantly. When Pod Identities are enabled as an Addon, (I assume that) EKS keeps editing this file whenever a Service Account Role mapping is created, using the eks create-pod-identity-association command.

The environment variables injected by the Webhook, points the SDK to perform a credentials lookup from a credentials server, and proceeds to use those credentials to authenticate the requests to AWS. This credentials server is the EKS Pod Identity Agent.

EKS Pod Identity Agent

The Agent (which is not the Webhook, I know, they are confusing) is a credentials server that sits on every Node as a Daemonset. When it receives a request for credentials, along with a Service Account token, it will pass the token along to EKS to exchange it to temporary credentials.

EKS

When the EKS Pod Identity Agent requests a credentials exchange, EKS performs an AssumeRoleForPodIdentity operation to assume the target role and get temporary credentials. For this to work, the EKS Node Instance profile should have the permission eks-auth:AssumeRoleForPodIdentity attached to it. The easiest way to make sure this happens is to attach the AWS managed policy AmazonEKSWorkerNodePolicy to the Node role when creating it.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "WorkerNodePermissions",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVolumes",
                "ec2:DescribeVolumesModifications",
                "ec2:DescribeVpcs",
                "eks:DescribeCluster",
                "eks-auth:AssumeRoleForPodIdentity"
            ],
            "Resource": "*"
        }
    ]
}

After this operation, the EKS Pod identity is returrned the temporary credentials which passes it back to the SDK on the Pod.

Conclusion

The complexity of the architecture is not really visible to the end user in EKS Pod Identities. They just have to,

  1. Create the IAM Role to use
  2. Create the K8s Service Account to map to the Role
  3. Map the Serivce Account to IAM Role in AWS
  4. Start using the Service Account for Pods

The approach recommended before EKS Pod Identities was introduced was equally complex in architecture and in how to set it up to get something out usefully. I will explore IAM Roles for Service Accounts (IRSA) in the next video.

Bibliography?

Links to documentation and code:

  1. Credential Provider Chain - https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html#credentialProviderChain
  2. Container Credentials Provider - https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html
  3. Java SDK - https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-core
  4. AssumeRoleForPodIdentity docs - https://docs.aws.amazon.com/eks/latest/APIReference/API_auth_AssumeRoleForPodIdentity.html
  5. TokenRequest docs - https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/
  6. Pod Identity Webhook Github - https://github.com/aws/amazon-eks-pod-identity-webhook
  7. Pod Identity Agent Github - https://github.com/aws/eks-pod-identity-agent