Kubernetes: ServiceAccount with AWS IAM Role for Kubernetes Pod
Tags: aws, security, kubernetes
Published: 2022-12-12 05:13:41

---
title: Kubernetes: ServiceAccount with AWS IAM Role for Kubernetes Pod
published: true
date: 2022-12-11 05:18:29 UTC
tags: aws,security,kubernetes
canonical_url: https://rtfm.co.ua/en/kubernetes-serviceaccount-z-aws-iam-role-dlya-kubernetes-pod-2/
---

### Kubernetes: ServiceAccount from AWS IAM Role for Kubernetes Pod

![](https://cdn-images-1.medium.com/max/318/1*X3phdxmrG9gpQFETH74efQ.png)

We have Grafana Loki for logs and need to connect an AWS IAM Role with AWS IAM Policy, which gives access to an AWS S3 bucket where Loki’s chunks and indexes will be stored.

IAM roles for Kubernetes Pods will work in the same way as IAM roles to EC2 instances: a process inside a Pod makes a request to the AWS API, and the AWS SDK or AWS CLI that makes the request also makes the [AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) request with the IAM Role to be used (see [AWS: rotation of user IAM keys, EC2 IAM Roles and Jenkins](https://rtfm.co.ua/en/aws-iam-users-keys-rotation-ec2-iam-roles-and-jenkins/) ).

To check how it will work in Kubernetes, let’s create a test IAM Role, ServiceAccount with the annotation of this role, and a Pod with this ServiceAccount that will use this Role.

Looking ahead — it works in Loki in some _alternative reality_, that is, even when you connect an already tested ServiceAccount to the Loki Pod — it crashes with errors. But eventually, I made it works even there (about setting up Loki itself with AWS S3 a little later in a separate post).

Documentation — [IAM roles for service accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html).

### IAM OIDC identity provider verification

In our case, the EKS cluster is deployed using the Terraform [`aws_eks_cluster`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster) module and the OpenID Connect (OIDC) provider should already be configured.

Go to the cluster page, and find _the OpenID Connect provider URL_ :

![](https://cdn-images-1.medium.com/max/981/0*E8MeFbPHHxg-E2gP.jpg)

Or from the terminal:

```
$ aws -rofile development --egion us-west-2 eks describe-cluster --name dev_data_services --query “cluster.identity.oidc.issuer” --output text
https://oidc.eks.us-west-2.amazonaws.com/id/537***A10
```

Copy the URL without `https://`, and find it in the _IAM > Identity providers_ :

![](https://cdn-images-1.medium.com/max/1024/0*1yhcKJZo2f-NGAMi.jpg)

Okay, that’s it.

### Creating a Kubernetes ServiceAccount with an AWS IAM role

First, let’s create an IAM policy that gives permissions to the AWS S3 bucket, then an IAM Role with a [`TrustedPolicy`](https://aws.amazon.com/ru/blogs/security/how-to-use-trust-policies-with-iam-roles/) that allows you to perform the [`AssumeRole`](https://rtfm.co.ua/ru/aws-iam-assumerole-opisanie-primery/), using the OIDC identity provider (IDP) of the cluster.

#### AWS IAM policy

Create a test policy:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::development-dev-loki-object-store",
                "arn:aws:s3:::development-dev-loki-object-store/*"
            ]
        }
    ]
}
```

Add it to the AWS IAM:

```
$ aws — profile development iam create-policy --policy-name test-iam-sa-pod-policy --policy-document file://test-iam-sa-pod-policy.json
```

Move on to the role.

#### AWS IAM role and TrustedPolicy

Find an **ARN** of your Identity Provider:

![](https://cdn-images-1.medium.com/max/1024/0*cxhh0MollGXOicPl.jpg)

The OIDC identity provider **URL** has already been found earlier:

```
$ aws --profile development --region us-west-2 eks describe-cluster --name dev_data_services --query “cluster.identity.oidc.issuer” --output text
https://oidc.eks.us-west-2.amazonaws.com/id/537***A10
```

#### Creating an IAM Role with the AWS CLI

Create a file with the TustedPolicy, in its `Principal` filed specify the **ARN** of the IDP, and in the `Condition` - the OIDC **URL** of the cluster, which will be allowed to perform requests to the _sts.amazonaws.com_ :

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::638 ***021:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/537*** A10"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.us-west-2.amazonaws.com/id/537***A10:aud": "sts.amazonaws.com"
                }
            }
        }
    ]
}
```

Create a role with this TrustedPolicy:

```
$ aws --profile development iam create-role --role-name test-iam-sa-pod-role --assume-role-policy-document file://test-iam-sa-role-trusted-policy.json
```

Connect the IAM Policy which we created above with permissions to the S3 to this IAM Role:

```
$ aws --profile development iam attach-role-policy --role-name test-iam-sa-pod-role --policy-arn=arn:aws:iam::638***021:policy/test-iam-sa-pod-policy
```

#### Create an IAM Role from the AWS Console

Or we can also do it through the Amazon Console page  -  choose the type of _Web identity_, _Identity Provider_ of the cluster, and _Audience_ :

![](https://cdn-images-1.medium.com/max/1024/0*esWQi56m9_cGBO8K.jpg)

Add the IAM Policy for S3:

![](https://cdn-images-1.medium.com/max/709/0*c_eyjMbFeVlImixV.png)

Save it:

![](https://cdn-images-1.medium.com/max/1024/0*aZuPjzdmoF0Rlb1s.jpg)

Copy the ARN of the role:

![](https://cdn-images-1.medium.com/max/1024/0*GPcx96nQb7csVyUC.jpg)

#### Creating a Kubernetes ServiceAccount

Create a ServiceAccount manifest, in its `annotations` set the ARN of the created role:

```
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-iam-sa-pod-service-account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::638***021:role/test-iam-sa-pod-role
```

And let’s go to the Kubernetes Pod.

### Running a Kubernetes Pod with a ServiceAccount

Create a manifest of the Pod with the `serviceAccountName` of the ServiceAccount, so the complete file will look like this:

```
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-iam-sa-pod-service-account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::638***021:role/test-iam-sa-pod-role
---
apiVersion: v1
kind: Pod
metadata:
  name: test-iam-sa-pod
  labels:
    app: test-iam-sa-app
spec:
  containers:
    - name: test-iam-sa
      image: amazon/aws-cli
      command: ["/bin/bash", "-c", "--"]
      args: ["while true; do sleep 30; done;"]
  serviceAccountName: test-iam-sa-pod-service-account
```

In the Pod, we will use a Docker image with AWS CLI with the `sleep` command, so it will stay _Running_ after startup.

Deploy the ServiceAccount and Pod:

```
$ kubectl apply -f test-iam-sa-pod.yaml
serviceaccount/test-iam-sa-pod-service-account created
pod/test-iam-sa-pod created
```

Go into it:

```
$ kubectl exec -ti test-iam-sa-pod — bash
```

And check access to the basket:

```
bash-4.2# aws s3 ls development-dev-loki-object-store
PRE test/
```

Done.

_Originally published at_ [_RTFM: Linux, DevOps, and system administration_](https://rtfm.co.ua/en/kubernetes-serviceaccount-z-aws-iam-role-dlya-kubernetes-pod-2/)_._

* * *