IAM roles for service sccounts¶
Introduction¶
Amazon EKS supports IAM Roles for Service Accounts (IRSA) that allows cluster operators to map AWS IAM Roles to Kubernetes Service Accounts.
This provides fine-grained permission management for apps that run on EKS and use other AWS services. These could be apps that use S3, any other data services (RDS, MQ, STS, DynamoDB), or Kubernetes components like AWS ALB Ingress controller or ExternalDNS.
You can easily create IAM Role and Service Account pairs with eksctl
.
NOTE: if you used instance roles, and are considering to use IRSA instead, you shouldn't mix the two.
How it works¶
It works via IAM OpenID Connect Provider (OIDC) that EKS exposes, and IAM Roles must be constructed with reference to the IAM OIDC Provider (specific to a given EKS cluster), and a reference to the Kubernetes Service Account it will be bound to.
Once an IAM Role is created, a service account should include the ARN of that role as an annotation (eks.amazonaws.com/role-arn
).
Inside EKS, there is an admission controller that injects AWS session credentials into pods respectively of the roles 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. Given a recent version of AWS SDK is used (see AWS documentation for details of exact version), the application will use these credentials.
In eksctl
the name of the resource is iamserviceaccount, which represents an IAM Role and Service Account pair.
Usage without config files¶
NOTE: IAM Roles for Service Accounts require Kubernetes version 1.13 or above.
The IAM OIDC Provider is not enabled by default, you can use the following command to enable it, or use config file (see below):
1 | eksctl utils associate-iam-oidc-provider --cluster=<clusterName>
|
Once you have the IAM OIDC Provider associated with the cluster, to create a IAM role bound to a service account, run:
1 | eksctl create iamserviceaccount --cluster=<clusterName> --name=<serviceAccountName> --namespace=<serviceAccountNamespace> --attach-policy-arn=<policyARN>
|
NOTE: you can specify
--attach-policy-arn
multiple times to use more then one policy.
More specifically, you can create a service account with read-only access to S3 by running:
1 | eksctl create iamserviceaccount --cluster=<clusterName> --name=s3-read-only --attach-policy-arn=arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
|
By default, it will be created in default
namespace, but you can specify any other namespace, e.g.:
1 | eksctl create iamserviceaccount --cluster=<clusterName> --name=s3-read-only --namespace=s3-app --attach-policy-arn=arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
|
NOTE: If the namespace doesn't exist already, it will be created.
If you have service account already created in the cluster (without an IAM Role), you will need to use --override-existing-serviceaccounts
flag.
Currently, to update a role you will need to re-create, run eksctl delete iamserviceaccount
followed by eksctl create iamserviceaccount
to achieve that.
Usage with config files¶
To manage iamserviceaccounts
using config file, you will be looking to set iam.withOIDC: true
and list account you want under iam.serviceAccount
.
All of the commands support --config-file
, you can manage iamserviceaccounts the same way as nodegroups.
The eksctl create iamserviceaccount
command supports --include
and --exclude
flags.
And the eksctl delete iamserviceaccount
command supports --only-missing
as well, so you can perform deletions the same way as nodegroups.
You use the following config example with eksctl create cluster
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | # An example of ClusterConfig with IAMServiceAccounts: --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: cluster-13 region: us-west-2 iam: withOIDC: true serviceAccounts: - metadata: name: s3-reader # if no namespace is set, "default" will be used; # the namespace will be created if it doesn't exist already namespace: backend-apps labels: {aws-usage: "application"} attachPolicyARNs: - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" - metadata: name: cache-access namespace: backend-apps labels: {aws-usage: "application"} attachPolicyARNs: - "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" - "arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess" - metadata: name: cluster-autoscaler namespace: kube-system labels: {aws-usage: "cluster-ops"} attachPolicy: # inline policy can be defined along with `attachPolicyARNs` Version: "2012-10-17" Statement: - Effect: Allow Action: - "autoscaling:DescribeAutoScalingGroups" - "autoscaling:DescribeAutoScalingInstances" - "autoscaling:DescribeLaunchConfigurations" - "autoscaling:DescribeTags" - "autoscaling:SetDesiredCapacity" - "autoscaling:TerminateInstanceInAutoScalingGroup" Resource: '*' nodeGroups: - name: "ng-1" tags: # EC2 tags required for cluster-autoscaler auto-discovery k8s.io/cluster-autoscaler/enabled: "true" k8s.io/cluster-autoscaler/cluster-13: "owned" desiredCapacity: 1 |
If you create a cluster without these fields set, you can use the following commands to enable all you need:
1 2 | eksctl utils associate-iam-oidc-provider --config-file=<path> eksctl create iamserviceaccount --config-file=<path> |