Simplifying AWS Services Access for pods with EKS Pod Identity

Temps de lecture : 6 minutes

In November 2023, AWS announced EKS Pod Identity, a new feature to facilitate the configuration of IAM permissions for pods hosted on Amazon Elastic Kubernetes Service EKS.

Prior to this announcement I had always been used to another method that I usually implement in my EKS clusters. IRSA for IAM Role for Service Accounts.

The main benefit of EKS Pod Identity is the simplicity it brings to automating the management of the permissions we give to applications in EKS clusters. If you’re a Terraform or CloudFormation user, I would advise you not to miss out on this feature, which will simplify your life, trust me. 😉

But before we get started on EKS Pod Identity, let’s take a quick look back.

At the beginning…

A Service Account is a Kubernetes concept that allows to give a pod an identity. The problem is that the concept of a Service Account does not exist on AWS. We think in terms of IAM Identities, such as users or roles.

When the EKS service was released, if we wanted to give a pod permission to access an AWS resource, such as an S3 bucket, we had no choice but to assign an IAM role to the node (EC2 Instance). 

And it was through this role that pods were granted the permissions to interact with AWS services. The major drawback of this method is that all pods deployed on a node share the same permissions. 

Disturbing when you are trying to apply a least privilege strategy to give each pod only the permissions it really needs…

2019, IRSA is released

To meet this need for finer control over pod permissions, AWS is releasing IRSA (IAM Role for Service Accounts) in September 2019.

This feature introduces a mechanism for associating a Service Account with an IAM Role. But to take advantage of this, we need to configure a few resources:

  • An OIDC Provider, to authenticate and authorise a Service Account using the OpenID connect protocol
  • A role trust policy to control which Service Account can assume a particular IAM role.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/<EKS_OIDC_PROVIDER_ID>"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.eu-west-1.amazonaws.com/id/<EKS_OIDC_PROVIDER_ID>:sub": "system:serviceaccount:<NAMESPACE>:<SERVICE_ACCOUNT>"
        }
      }
    }
  ]
}
  • An IAM role containing the usual permissions for accessing AWS resources
  • A Service Account with a specific annotation referring to the IAM role you want to associate. 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-iam-role

The drawback of this feature is that when you want to automate the creation of a cluster with IRSA, you may face with a number of challenges:

  • The fact that some configuration parameters are only known once the cluster has been created. Like the OIDC provider URL dedicated to the cluster, required to configure the IAM role and Kubernetes Service Account.
  • There has to be an OIDC provider for each cluster, which can cause problems when you are doing Blue/Green deployment, for example, and you want to share an IAM Role for pods running on different clusters. In this case, you need to update the Trust Policy to authorise the OIDC provider for the new cluster.
  • Certain limitations may be encountered, especially on the size of Trust Policies, the number of IAM Roles or the maximum number of Identity Providers that can be created on an AWS account.
  • When you need to create new clusters frequently, you may be slowed by the fact that you have to wait several minutes for the cluster to be created and ready to be registered with the OIDC when it is created.

2023, EKS Pod Identity

AWS has taken customer feedback on board, and in November 2023 launched EKS Pod Identity.

From now on, you no longer need to configure an OIDC Provider! But instead a new Amazon EKS Pod Identity Agent add-on that can be installed directly when a new cluster is created.

As for the Trust Policy to be defined for an IAM Role to be assumed by a pod, all you have to do is specify pods.eks.amazonaws.com as the main service and give permission to add IAM Session Tags. We will see why later on 😉

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

To associate a Service Account with an IAM Role, all that remains is to create a new type of resource called Pod Identity Association, which you configure by specifying the IAM Role, the Service Account and the Namespace you want to link to your pod.

Automating the creation of all these resources makes configuration much simpler. For example, here’s an example of Terraform code to install an EKS Pod Identity agent, an IAM Role and the association between IAM Role and Service Account on the fly !

# Install EKS Pod Identity Agent on EKS Cluster
resource "aws_eks_addon" "example" {
  cluster_name = "revolve"
  addon_name   = "eks-pod-identity-agent"
}

# Trust Policy for IAM Role
data "aws_iam_policy_document" "assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }

    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]
  }
}
# Policy that gives Read Only access to an S3 Bucket
data "aws_iam_policy_document" "pod_policy" {
  statement {
    effect = "Allow"

    actions = [
      "s3:GetObject",
    ]

    resources = [
      "s3://my-bucket/*",
    ]
  }
}


# IAM Role and its associated policy. 
resource "aws_iam_role" "pod_role" {
  name = "S3ReadOnlyForPodsRole"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
  policy = data.aws_iam_policy_document.pod_policy.json
}


# Here is where the magic happens! We map our IAM role to a pod by specifing its Cluster, Namespace and Service Account 
resource "aws_eks_pod_identity_association" "example" {
  cluster_name    = "revolve"
  namespace       = "project"
  service_account = "app"
  role_arn        = aws_iam_role.pod_role.arn
}

Earlier we were talking about allowing IAM Session Tags to be added to Trust Policy.

Another feature added by EKS Pod Identity to facilitate and control the reuse of a role for pods running on a different cluster, Namespace or Service Account is the use of IAM Session Tags. 

Here is a list of those that are automatically added by EKS Pod Identity to the temporary credentials used by a pod.

  • eks-cluster-arn
  • eks-cluster-name
  • kubernetes-namespace
  • kubernetes-service-account
  • kubernetes-pod-name
  • kubernetes-pod-uid

Going back to our previous example, we can now filter certain pod actions based on the cluster where it is deployed by adding Session Tags based conditions.

In this example we define a policy that allows read access on S3 objects based on a specific eks-cluster-name Session Tag.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectTagging"
            ],
            "Resource": "arn:aws:s3:::my-bucket/*",
            "Condition": {
                "StringEquals": {
                    "s3:ExistingObjectTag/eks-cluster-name": "${aws:PrincipalTag/eks-cluster-name}"
                }
            }
        }
    ]
}

If you would  like to find out more about how EKS Pod Identity works, I highly recommend reading this official AWS documentation as well as this article written by Datadog’s security teams.

Key Takeaways

To conclude, EKS Pod Identity is a feature that simplifies permissions management for pods in EKS clusters, especially for people like me who are used to automating provisioning with IaC (Terraform). The key point here is that you no longer need to configure an OIDC Provider for each cluster and Trust Policies are simplified. 

The association of a Service Account with an IAM role also becomes much simpler and easier. 

Finally, EKS Pod Identity lets us control securely the reuse of an IAM role for pods running on different clusters, namespaces or using different Service Account, thanks to IAM Session Tags.

So now… are you convinced to switch from IRSA to EKS Pod Identity? 🙂

Commentaires :

A lire également sur le sujet :