How to assign AWS IAM Role to Service Account with Terraform?

10/7/2020

I have a Kubernetes EKS cluster on AWS, an my goal is to be able to watch particular config maps in my Spring Boot application. On my local environment everything works correctly, but when I use this setup inside AWS I get forbidden state and my application fails to run. I've created a Service Account but don't understand how to create Terraform script which can assign the needed IAM Role. Any help would be appreciated.

-- xeLL
amazon-eks
amazon-iam
amazon-web-services
kubernetes
terraform

3 Answers

10/5/2021

I think you missed something here..you should add trust relationship between the role and the oidc provider as described here:

enter image description here

enter image description here

-- yishaihl
Source: StackOverflow

10/7/2020

This depends on several things.

An AWS IAM Role can be provided to Pods in different ways, but the recommended way now is to use IAM Roles for Service Accounts, IRSA.

Depending on how you provision the Kubernetes cluster with Terraform, this is also done in different ways. If you use AWS EKS and provision the cluster using the Terraform AWS EKS module, then you should set enable_irsa to true.

You then need to create an IAM Role for you application (Pods), and you need to return the ARN for the IAM Role. This can be done using the aws_iam_role resource.

You need to create a Kubernetes ServiceAccount for your pod, it can be created with Terraform, but many want to use Yaml for Kubernetes resources. The ServiceAccount need to be annotated with the IAM Role ARN, like:

annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::14xxx84:role/my-iam-role

See the EKS workshop for IAM Roles for Service Accounts lesson for a guide through this. However, it does not use Terraform.

-- Jonas
Source: StackOverflow

12/10/2020

First I created the necessary role using below code:

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

    condition {
      test     = "StringEquals"
      variable = "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub"
      values   = ["system:serviceaccount:kube-system:aws-node"]
    }

    principals {
      identifiers = [aws_iam_openid_connect_provider.eks.arn]
      type        = "Federated"
    }
  }
}

# create a role that can be attached to pods.
resource "aws_iam_role" "eks_pods" {
  assume_role_policy = data.aws_iam_policy_document.eks_pods.json
  name               = "eks-pods-iam-role01"

  depends_on = [aws_iam_openid_connect_provider.eks]
}

resource "aws_iam_role_policy_attachment" "aws_pods" {
  role       = aws_iam_role.eks_pods.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  depends_on = [aws_iam_role.eks_pods]
}

Then I used the below command to attach the role created to the service account. I have not found any way to do it from within terraform:

kubectl annotate serviceaccount -n kube-system aws-node eks.amazonaws.com/role-arn=arn:aws:iam::<your_account>:role/eks-pods-iam-role01

Then you can verify your service account, it should show the new annotations.

kubectl describe sa aws-node -n kube-system
Name:                aws-node
Namespace:           kube-system
Labels:              <none>
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::<ur_account>:role/eks-pods-iam-role01
Image pull secrets:  <none>
Mountable secrets:   aws-node-token-xxxxx
Tokens:              aws-node-token-xxxxx
Events:              <none>
-- Chinmaya Biswal
Source: StackOverflow