AWS IAM authentication for pods in EKS : IRSA - with examples

Samuel Bagattin
5 min readApr 5, 2022

--

I have been working with Kubernetes on AWS using EKS for some time, so I wanted to share a better way than using EC2 instance profile to authenticate pods to AWS APIs.

In this article I will show how to setup IAM Roles for Service Accounts (IRSA) using Terraform and Kubernetes manifests, and how to use this authentication mechanism with a microservice running in the cluster.

Unlike kube2iam or kiam, IRSA is the official AWS way to authenticate pods to AWS API.

The full source code used to create an test all the components — the EKS cluster, the Kubernetes resources, the application and its associated Dockerfile — are publicly available in this GitHub repository.

Architecture

Diagram showing how a pod is authenticating to STS using IRSA
Architecture — Pod authenticating the AWS API using IRSA

The schema below shows the necessary setup to get security credentials to access the AWS API, using an IAM Role dedicated to its service account.

There are several components to take into account :

  • An up and running EKS cluster
  • An IAM Identity Provider configured to authenticate resources from the EKS cluster throught the OpenID Connect protocol (OIDC), to the AWS Account
  • A running pod and its associated service account
  • An IAM role with a trust policy allowing the previous service account to perform AssumeRoleWithWebIdentity
  • The process during which the pod obtains temporary STS security credentials, to authenticate to AWS API through the role’s identity

AWS IAM Setup

This section assumes that you already have an EKS Cluster up and running.

The full Terraform source code (including the EKS cluster and node group) is available in here :

First, we need to create an IAM OIDC provider in the AWS account referencing the cluster’s OIDC issuer url.

IAM OIDC provider creation

Then, to authenticate our app to the AWS API, we need to create an IAM role

This role will be assumable only by pods that will mount a specific Kubernetes service-account.

IAM role creation

As you can see below, the trust policy of the role has the following specifications :

  • Allows assuming the role only through AssumeRoleWithWebIdentity API call
  • Only if the requester has the identity of the serviceaccount my-serviceaccount located in the default namespace
  • Only if the request has been made through the previously create OIDC provider
  • Finally, we create the IAM role and its associated permissions.

This sample code has been inspired from the Terraform documentation

Kubernetes resources setup

We will now create the Kubernetes service-account and associate it to the IAM role.

The manifest below creates the service-account my-serviceaccount in the namespace default

Note the eks.amazonaws.com/role-arn annotation : this is the one attribute that will help the app know which IAM role to assume (full documentation can be found in the AWS website)

Now we can create a pod (or any Kubernetes resource that manages pods).

This pod manifest creates a pod mounting the service-account previously created, and starts our app.

The container image used has been built from the app we will create at the end of this article

Kubernetes pod-identity mutating webhook configuration

To help with authenticating pod to the AWS API, a brand new EKS cluster will come with a mutating webhook configuration named pod-identity-webhook.

Here is a sample manifest of this resource (no need to apply it):

When a pod is created in any namespace, for each container located in the namespace, the webhook creates the following environment variables in the manifest :

  • AWS_STS_REGIONAL_ENDPOINTS set to regional by default, tells the SDK to use the current region endpoint to issue STS API calls
  • AWS_DEFAULT_REGION and AWS_REGION set to the region in which the cluster is running
  • AWS_ROLE_ARN set to the ARN of the IAM role you specified in the eks.amazonaws.com/role-arn service-account annotation
  • AWS_WEB_IDENTITY_TOKEN_FILE contains the path where is stored the Kubernetes service account token. This token will be used to get temporary STS credentials (usually set to /var/run/secrets/eks.amazonaws.com/serviceaccount/token)

Authenticating a microservice

Now that all infrastructure and Kubernetes resources are setup, we can develop and deploy an app running in the cluster, that will use the previously described authentication mechanism

I will use a simple Golang app to perform the authentication and issue API calls using the AWS SDK, but the steps should be fairly similar in any other language.

As usual the full source code can be found here :

We assume that you already have a Golang app with the AWS SDK installed and an empty main function present.

The previous code sample :

  • Creates a new session using the default credentials chain
  • Creates an STS client to receive the temporary credentials
  • Gets the service account token associated to the pod
  • Gets the ARN of the role that will be assumed

Now we can get temporary credentials and issue API calls using the IAM role.

This code performs the following operations :

  • Requests temporary STS credentials using AssumeRoleWithWebIdentity by specifying the previously obtained role ARN and SA token, as well as the session duration and the session name.
  • Creates a new session using the temporary credentials
  • Creates a new STS client using the new identity and prints authentication information about the current session
  • Creates an S3 client using the same identity to test the permissions we gave previously to the role

Once built into a container image and deployed using the previous pod manifest, the application will output similar logs :

Here we go ! Your application now has its own role and its own set of permissions thanks to IRSA 🚀

For further investigation on the full authentication process with OIDC, check out this great blog post from AWS.

--

--

Samuel Bagattin

Senior Cloud Engineer, I work with Cloud technologies, automation tools and Kubernetes everyday.