Usually, when we had to use a service from an external provider, we injected the service credential (connection string, secret, token, etc.) in the application (from a Key Vault, environment variable, app settings, etc.). But in AWS, there is the concept of IAM Roles that could make life much easier (and safer).
An IAM role is similar to an IAM user, in that it is an AWS identity with permission policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.
From the text above, we can tell EKS to run a Pod using a specific IAM Role and control the access needed by the application against the AWS services. As a first step, we are going to create an IAM Role with the OpenID Connect provider URL of your EKS Cluster:
Now we can create the AWS Role (AIM-> Roles -> Create Role). Choose as trusted entity type the Web Identity
option:
If your Identity Provider is not on the list, create a new one following these instructions. Time to add the permission for the IAM Role:
Give a name to the AIM Role and save it.
Go to the IAM Role recently created and change the thrust policy to:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::[AWS_ACCOUNT_ID]:oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/[OIDC_ID]"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"oidc.eks.us-east-2.amazonaws.com/id/[OIDC_ID]:aud": "system:serviceaccount:demo-namespace:*"
}
}
}
]
}
The condition used will help us assign the AIM Role to every Service Account in a specific Namespace. If this condition doesn't fit your requirements feel free to change it. Copy the AIM Role's ARN because next, we are going to create the Service Account:
apiVersion: v1
kind: ServiceAccount
metadata:
name: demo-sa
namespace: demo-namespace
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::[AWS_ACCOUNT_ID]:role/eks-demo-role
And to asssign it to a Pod (thru a Deployment):
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: demo
spec:
replicas: 2
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
serviceAccountName: demo-sa
containers:
- name: api-deployment-container
env:
- name: ASPNETCORE_ENVIRONMENT
value: Development
image: [AWS_ACCOUNT_ID].dkr.ecr.us-east-2.amazonaws.com/demo-api:3.0
ports:
- name: http
containerPort: 80
protocol: TCP
And that's it EKS injects the AWS session credentials based on the annotation on the Service Account used by the Pod. The credentials will get exposed by AWS_ROLE_ARN
& AWS_WEB_IDENTITY_TOKEN_FILE
environment variables. The AWS SDK used by your application will use these credentials to connect to the AWS services.
Here you can find more information for further exploration on it.