IRSA: How to create an IAM role for a specific ServiceAccount

2 min read | by Jordi Prats

On AWS EKS you can associate an IAM role with a Kubernetes service account. The assume role policy is going to look like this:

  "Version": "2012-10-17",
  "Statement": [
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789123:oidc-provider/"
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "": "system:serviceaccount:demons:demosa"

Let's take a look on how to create this role using Terraform

First we will have to make sure that we have created an IAM OIDC provider for our cluster. We'll need to construct the IRSA policy using the OIDC URL and the account ID.

We can the the OIDC URL using the following command:

$ aws eks describe-cluster --name prod --query "cluster.identity.oidc.issuer" --output text

On terraform we can get the account ID using the aws_caller_identity datasource:

data "aws_caller_identity" "current" {}

So assuming that we have the OIDC URL, the namespace where the ServiceAccount is going to sit and it's name as an input variables:

variable "namespace" {
  description = "Kubernetes namespace for the service account"
  type        = string

variable "serviceaccount" {
  description = "ServiceAccount name"
  type        = string

variable "oidc_url" {
  description = "OpenID Connect provider URL"

We can create the policy as follows:

locals {
  oidc_provider = replace(var.oidc_url, "https://", "")

data "aws_iam_policy_document" "assume_role_policy" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    effect  = "Allow"

    condition {
      test     = "StringEquals"
      variable = "${local.oidc_provider}:sub"
      values   = ["system:serviceaccount:${var.namespace}:${var.serviceaccount}"]

    principals {
      identifiers = ["arn:aws:iam::${}:oidc-provider/${local.oidc_provider}"]
      type        = "Federated"

To finally create an IAM role with that assume_role_policy policy:

resource "aws_iam_role" "iam_role" {
  name                  = "${var.role_name}"
  assume_role_policy    = data.aws_iam_policy_document.assume_role_policy.json
  force_detach_policies = true

On the Kubernetes side, we will have to create an annotation for the ServiceAccount to actually using the IAM role using it's ARN, for example:

apiVersion: v1
kind: ServiceAccount
  annotations: arn:aws:iam::123456789123:role/demoirsa
  name: demosa

Posted on 24/11/2021