

 **Help improve this page** 

To contribute to this user guide, choose the **Edit this page on GitHub** link that is located in the right pane of every page.

# IAM roles for service accounts
<a name="iam-roles-for-service-accounts"></a>

**Tip**  
 [Register](https://aws-experience.com/emea/smb/events/series/get-hands-on-with-amazon-eks?trk=4a9b4147-2490-4c63-bc9f-f8a84b122c8c&sc_channel=el) for upcoming Amazon EKS workshops.

Applications in a Pod’s containers can use an AWS SDK or the AWS CLI to make API requests to AWS services using AWS Identity and Access Management (IAM) permissions. Applications must sign their AWS API requests with AWS credentials. **IAM roles for service accounts (IRSA)** provide the ability to manage credentials for your applications, similar to the way that Amazon EC2 instance profiles provide credentials to Amazon EC2 instances. Instead of creating and distributing your AWS credentials to the containers or using the Amazon EC2 instance’s role, you associate an IAM role with a Kubernetes service account and configure your Pods to use the service account. You can’t use IAM roles for service accounts with [local clusters for Amazon EKS on AWS Outposts](eks-outposts-local-cluster-overview.md).

IAM roles for service accounts provide the following benefits:
+  **Least privilege** – You can scope IAM permissions to a service account, and only Pods that use that service account have access to those permissions. This feature also eliminates the need for third-party solutions such as `kiam` or `kube2iam`.
+  **Credential isolation** – When access to the [Amazon EC2 Instance Metadata Service (IMDS)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) is restricted, a Pod’s containers can only retrieve credentials for the IAM role that’s associated with the service account that the container uses. A container never has access to credentials that are used by other containers in other Pods. If IMDS is not restricted, the Pod’s containers also have access to the [Amazon EKS node IAM role](create-node-role.md) and the containers may be able to gain access to credentials of IAM roles of other Pods on the same node. For more information, see [Restrict access to the instance profile assigned to the worker node](https://docs.aws.amazon.com/eks/latest/best-practices/identity-and-access-management.html#_identities_and_credentials_for_eks_pods_recommendations).

**Note**  
Pods configured with `hostNetwork: true` will always have IMDS access, but the AWS SDKs and CLI will use IRSA credentials when enabled.
+  **Auditability** – Access and event logging is available through AWS CloudTrail to help ensure retrospective auditing.

**Important**  
Containers are not a security boundary, and the use of IAM roles for service accounts does not change this. Pods assigned to the same node will share a kernel and potentially other resources depending on your Pod configuration. While Pods running on separate nodes will be isolated at the compute layer, there are node applications that have additional permissions in the Kubernetes API beyond the scope of an individual instance. Some examples are `kubelet`, `kube-proxy`, CSI storage drivers, or your own Kubernetes applications.

Enable IAM roles for service accounts by completing the following procedures:

1.  [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md) – You only complete this procedure once for each cluster.
**Note**  
If you enabled the EKS VPC endpoint, the EKS OIDC service endpoint couldn’t be accessed from inside that VPC. Consequently, your operations such as creating an OIDC provider with `eksctl` in the VPC will not work and will result in a timeout when attempting to request `https://oidc.eks.region.amazonaws.com`. An example error message follows:  

   ```
   server cant find oidc.eks.region.amazonaws.com: NXDOMAIN
   ```
To complete this step, you can run the command outside the VPC, for example in AWS CloudShell or on a computer connected to the internet. Alternatively, you can create a split-horizon conditional resolver in the VPC, such as Route 53 Resolver to use a different resolver for the OIDC Issuer URL and not use the VPC DNS for it. For an example of conditional forwarding in CoreDNS, see the [Amazon EKS feature request](https://github.com/aws/containers-roadmap/issues/2038) on GitHub.

1.  [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md) – Complete this procedure for each unique set of permissions that you want an application to have.

1.  [Configure Pods to use a Kubernetes service account](pod-configuration.md) – Complete this procedure for each Pod that needs access to AWS services.

1.  [Use IRSA with the AWS SDK](iam-roles-for-service-accounts-minimum-sdk.md) – Confirm that the workload uses an AWS SDK of a supported version and that the workload uses the default credential chain.

## IAM, Kubernetes, and OpenID Connect (OIDC) background information
<a name="irsa-oidc-background"></a>

In 2014, AWS Identity and Access Management added support for federated identities using OpenID Connect (OIDC). This feature allows you to authenticate AWS API calls with supported identity providers and receive a valid OIDC JSON web token (JWT). You can pass this token to the AWS STS `AssumeRoleWithWebIdentity` API operation and receive IAM temporary role credentials. You can use these credentials to interact with any AWS service, including Amazon S3 and DynamoDB.

Each JWT token is signed by a signing key pair. The keys are served on the OIDC provider managed by Amazon EKS and the private key rotates every 7 days. Amazon EKS keeps the public keys until they expire. If you connect external OIDC clients, be aware that you need to refresh the signing keys before the public key expires. Learn how to [Fetch signing keys to validate OIDC tokens](irsa-fetch-keys.md).

Kubernetes has long used service accounts as its own internal identity system. Pods can authenticate with the Kubernetes API server using an auto-mounted token (which was a non-OIDC JWT) that only the Kubernetes API server could validate. These legacy service account tokens don’t expire, and rotating the signing key is a difficult process. In Kubernetes version `1.12`, support was added for a new `ProjectedServiceAccountToken` feature. This feature is an OIDC JSON web token that also contains the service account identity and supports a configurable audience.

Amazon EKS hosts a public OIDC discovery endpoint for each cluster that contains the signing keys for the `ProjectedServiceAccountToken` JSON web tokens so external systems, such as IAM, can validate and accept the OIDC tokens that are issued by Kubernetes.

# Create an IAM OIDC provider for your cluster
<a name="enable-iam-roles-for-service-accounts"></a>

Your cluster has an [OpenID Connect](https://openid.net/connect/) (OIDC) issuer URL associated with it. To use AWS Identity and Access Management (IAM) roles for service accounts, an IAM OIDC provider must exist for your cluster’s OIDC issuer URL.

## Prerequisites
<a name="_prerequisites"></a>
+ An existing Amazon EKS cluster. To deploy one, see [Get started with Amazon EKS](getting-started.md).
+ Version `2.12.3` or later or version `1.27.160` or later of the AWS Command Line Interface (AWS CLI) installed and configured on your device or AWS CloudShell. To check your current version, use `aws --version | cut -d / -f2 | cut -d ' ' -f1`. Package managers such as `yum`, `apt-get`, or Homebrew for macOS are often several versions behind the latest version of the AWS CLI. To install the latest version, see [Installing](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) and [Quick configuration with aws configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) in the * AWS Command Line Interface User Guide*. The AWS CLI version that is installed in AWS CloudShell might also be several versions behind the latest version. To update it, see [Installing AWS CLI to your home directory](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software) in the * AWS CloudShell User Guide*.
+ The `kubectl` command line tool is installed on your device or AWS CloudShell. The version can be the same as or up to one minor version earlier or later than the Kubernetes version of your cluster. For example, if your cluster version is `1.29`, you can use `kubectl` version `1.28`, `1.29`, or `1.30` with it. To install or upgrade `kubectl`, see [Set up `kubectl` and `eksctl`](install-kubectl.md).
+ An existing `kubectl` `config` file that contains your cluster configuration. To create a `kubectl` `config` file, see [Connect kubectl to an EKS cluster by creating a kubeconfig file](create-kubeconfig.md).

You can create an IAM OIDC provider for your cluster using `eksctl` or the AWS Management Console.

## Create OIDC provider (eksctl)
<a name="_create_oidc_provider_eksctl"></a>

1. Version `0.215.0` or later of the `eksctl` command line tool installed on your device or AWS CloudShell. To install or update `eksctl`, see [Installation](https://eksctl.io/installation) in the `eksctl` documentation.

1. Determine the OIDC issuer ID for your cluster.

   Retrieve your cluster’s OIDC issuer ID and store it in a variable. Replace `<my-cluster>` with your own value.

   ```
   cluster_name=<my-cluster>
   oidc_id=$(aws eks describe-cluster --name $cluster_name --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
   echo $oidc_id
   ```

1. Determine whether an IAM OIDC provider with your cluster’s issuer ID is already in your account.

   ```
   aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4
   ```

   If output is returned, then you already have an IAM OIDC provider for your cluster and you can skip the next step. If no output is returned, then you must create an IAM OIDC provider for your cluster.

1. Create an IAM OIDC identity provider for your cluster with the following command.

   ```
   eksctl utils associate-iam-oidc-provider --cluster $cluster_name --approve
   ```
**Note**  
If you enabled the EKS VPC endpoint, the EKS OIDC service endpoint couldn’t be accessed from inside that VPC. Consequently, your operations such as creating an OIDC provider with `eksctl` in the VPC will not work and will result in a timeout. An example error message follows:  

   ```
   ** server cant find oidc.eks.<region-code>.amazonaws.com: NXDOMAIN
   ```

   To complete this step, you can run the command outside the VPC, for example in AWS CloudShell or on a computer connected to the internet. Alternatively, you can create a split-horizon conditional resolver in the VPC, such as Route 53 Resolver to use a different resolver for the OIDC Issuer URL and not use the VPC DNS for it. For an example of conditional forwarding in CoreDNS, see the [Amazon EKS feature request](https://github.com/aws/containers-roadmap/issues/2038) on GitHub.

## Create OIDC provider (AWS Console)
<a name="create_oidc_provider_shared_aws_console"></a>

1. Open the [Amazon EKS console](https://console.aws.amazon.com/eks/home#/clusters).

1. In the left pane, select **Clusters**, and then select the name of your cluster on the **Clusters** page.

1. In the **Details** section on the **Overview** tab, note the value of the **OpenID Connect provider URL**.

1. Open the IAM console at https://console.aws.amazon.com/iam/.

1. In the left navigation pane, choose **Identity Providers** under **Access management**. If a **Provider** is listed that matches the URL for your cluster, then you already have a provider for your cluster. If a provider isn’t listed that matches the URL for your cluster, then you must create one.

1. To create a provider, choose **Add provider**.

1. For **Provider type**, select **OpenID Connect**.

1. For **Provider URL**, enter the OIDC provider URL for your cluster.

1. For **Audience**, enter `sts.amazonaws.com`.

1. (Optional) Add any tags, for example a tag to identify which cluster is for this provider.

1. Choose **Add provider**.

Next step: [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md) 

# Assign IAM roles to Kubernetes service accounts
<a name="associate-service-account-role"></a>

This topic covers how to configure a Kubernetes service account to assume an AWS Identity and Access Management (IAM) role. Any Pods that are configured to use the service account can then access any AWS service that the role has permissions to access.

## Prerequisites
<a name="_prerequisites"></a>
+ An existing cluster. If you don’t have one, you can create one by following one of the guides in [Get started with Amazon EKS](getting-started.md).
+ An existing IAM OpenID Connect (OIDC) provider for your cluster. To learn if you already have one or how to create one, see [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md).
+ Version `2.12.3` or later or version `1.27.160` or later of the AWS Command Line Interface (AWS CLI) installed and configured on your device or AWS CloudShell. To check your current version, use `aws --version | cut -d / -f2 | cut -d ' ' -f1`. Package managers such as `yum`, `apt-get`, or Homebrew for macOS are often several versions behind the latest version of the AWS CLI. To install the latest version, see [Installing](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) and [Quick configuration with aws configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) in the * AWS Command Line Interface User Guide*. The AWS CLI version that is installed in AWS CloudShell might also be several versions behind the latest version. To update it, see [Installing AWS CLI to your home directory](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software) in the * AWS CloudShell User Guide*.
+ The `kubectl` command line tool is installed on your device or AWS CloudShell. The version can be the same as or up to one minor version earlier or later than the Kubernetes version of your cluster. For example, if your cluster version is `1.29`, you can use `kubectl` version `1.28`, `1.29`, or `1.30` with it. To install or upgrade `kubectl`, see [Set up `kubectl` and `eksctl`](install-kubectl.md).
+ An existing `kubectl` `config` file that contains your cluster configuration. To create a `kubectl` `config` file, see [Connect kubectl to an EKS cluster by creating a kubeconfig file](create-kubeconfig.md).

## Step 1: Create IAM Policy
<a name="irsa-associate-role-procedure"></a>

If you want to associate an existing IAM policy to your IAM role, skip to the next step.

1. Create an IAM policy. You can create your own policy, or copy an AWS managed policy that already grants some of the permissions that you need and customize it to your specific requirements. For more information, see [Creating IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html) in the *IAM User Guide*.

1. Create a file that includes the permissions for the AWS services that you want your Pods to access. For a list of all actions for all AWS services, see the [Service Authorization Reference](https://docs.aws.amazon.com/service-authorization/latest/reference/).

   You can run the following command to create an example policy file that allows read-only access to an Amazon S3 bucket. You can optionally store configuration information or a bootstrap script in this bucket, and the containers in your Pod can read the file from the bucket and load it into your application. If you want to create this example policy, copy the following contents to your device. Replace *my-pod-secrets-bucket* with your bucket name and run the command.

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "s3:GetObject",
               "Resource": "arn:aws:s3:::my-pod-secrets-bucket"
           }
       ]
   }
   ```

1. Create the IAM policy.

   ```
   aws iam create-policy --policy-name my-policy --policy-document file://my-policy.json
   ```

## Step 2: Create and associate IAM Role
<a name="_step_2_create_and_associate_iam_role"></a>

Create an IAM role and associate it with a Kubernetes service account. You can use either `eksctl` or the AWS CLI.

### Create and associate role (eksctl)
<a name="_create_and_associate_role_eksctl"></a>

This `eksctl` command creates a Kubernetes service account in the specified namespace, creates an IAM role (if it doesn’t exist) with the specified name, attaches an existing IAM policy ARN to the role, and annotates the service account with the IAM role ARN. Be sure to replace the sample placeholder values in this command with your specific values. To install or update `eksctl`, see [Installation](https://eksctl.io/installation) in the `eksctl` documentation.

```
eksctl create iamserviceaccount --name my-service-account --namespace default --cluster my-cluster --role-name my-role \
    --attach-policy-arn arn:aws:iam::111122223333:policy/my-policy --approve
```

**Important**  
If the role or service account already exist, the previous command might fail. `eksctl` has different options that you can provide in those situations. For more information run `eksctl create iamserviceaccount --help`.

### Create and associate role (AWS CLI)
<a name="create_and_associate_role_shared_aws_cli"></a>

If you have an existing Kubernetes service account that you want to assume an IAM role, then you can skip this step.

1. Create a Kubernetes service account. Copy the following contents to your device. Replace *my-service-account* with your desired name and *default* with a different namespace, if necessary. If you change *default*, the namespace must already exist.

   ```
   cat >my-service-account.yaml <<EOF
   apiVersion: v1
   kind: ServiceAccount
   metadata:
     name: my-service-account
     namespace: default
   EOF
   kubectl apply -f my-service-account.yaml
   ```

1. Set your AWS account ID to an environment variable with the following command.

   ```
   account_id=$(aws sts get-caller-identity --query "Account" --output text)
   ```

1. Set your cluster’s OIDC identity provider to an environment variable with the following command. Replace *my-cluster* with the name of your cluster.

   ```
   oidc_provider=$(aws eks describe-cluster --name my-cluster --region $AWS_REGION --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
   ```

1. Set variables for the namespace and name of the service account. Replace *my-service-account* with the Kubernetes service account that you want to assume the role. Replace *default* with the namespace of the service account.

   ```
   export namespace=default
   export service_account=my-service-account
   ```

1. Run the following command to create a trust policy file for the IAM role. If you want to allow all service accounts within a namespace to use the role, then copy the following contents to your device. Replace *StringEquals* with `StringLike` and replace *\$1service\$1account* with `*`. You can add multiple entries in the `StringEquals` or `StringLike` conditions to allow multiple service accounts or namespaces to assume the role. To allow roles from a different AWS account than the account that your cluster is in to assume the role, see [Authenticate to another account with IRSA](cross-account-access.md) for more information.

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Federated": "arn:aws:iam::123456789012:oidc-provider/$oidc_provider"
         },
         "Action": "sts:AssumeRoleWithWebIdentity",
         "Condition": {
           "StringEquals": {
             "$oidc_provider:aud": "sts.amazonaws.com",
             "$oidc_provider:sub": "system:serviceaccount:$namespace:$service_account"
           }
         }
       }
     ]
   }
   ```

1. Create the role. Replace *my-role* with a name for your IAM role, and *my-role-description* with a description for your role.

   ```
   aws iam create-role --role-name my-role --assume-role-policy-document file://trust-relationship.json --description "my-role-description"
   ```

1. Attach an IAM policy to your role. Replace *my-role* with the name of your IAM role and *my-policy* with the name of an existing policy that you created.

   ```
   aws iam attach-role-policy --role-name my-role --policy-arn=arn:aws:iam::$account_id:policy/my-policy
   ```

1. Annotate your service account with the Amazon Resource Name (ARN) of the IAM role that you want the service account to assume. Replace *my-role* with the name of your existing IAM role. Suppose that you allowed a role from a different AWS account than the account that your cluster is in to assume the role in a previous step. Then, make sure to specify the AWS account and role from the other account. For more information, see [Authenticate to another account with IRSA](cross-account-access.md).

   ```
   kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
   ```

1. (Optional) [Configure the AWS Security Token Service endpoint for a service account](configure-sts-endpoint.md). AWS recommends using a regional AWS STS endpoint instead of the global endpoint. This reduces latency, provides built-in redundancy, and increases session token validity.

## Step 3: Confirm configuration
<a name="irsa-confirm-role-configuration"></a>

1. Confirm that the IAM role’s trust policy is configured correctly.

   ```
   aws iam get-role --role-name my-role --query Role.AssumeRolePolicyDocument
   ```

   An example output is as follows.

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
               },
               "Action": "sts:AssumeRoleWithWebIdentity",
               "Condition": {
                   "StringEquals": {
                       "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:default:my-service-account",
                       "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
                   }
               }
           }
       ]
   }
   ```

1. Confirm that the policy that you attached to your role in a previous step is attached to the role.

   ```
   aws iam list-attached-role-policies --role-name my-role --query "AttachedPolicies[].PolicyArn" --output text
   ```

   An example output is as follows.

   ```
                  arn:aws:iam::111122223333:policy/my-policy
   ```

1. Set a variable to store the Amazon Resource Name (ARN) of the policy that you want to use. Replace *my-policy* with the name of the policy that you want to confirm permissions for.

   ```
   export policy_arn=arn:aws:iam::111122223333:policy/my-policy
   ```

1. View the default version of the policy.

   ```
   aws iam get-policy --policy-arn $policy_arn
   ```

   An example output is as follows.

   ```
   {
       "Policy": {
           "PolicyName": "my-policy",
           "PolicyId": "EXAMPLEBIOWGLDEXAMPLE",
           "Arn": "arn:aws:iam::111122223333:policy/my-policy",
           "Path": "/",
           "DefaultVersionId": "v1",
           [...]
       }
   }
   ```

1. View the policy contents to make sure that the policy includes all the permissions that your Pod needs. If necessary, replace *1* in the following command with the version that’s returned in the previous output.

   ```
   aws iam get-policy-version --policy-arn $policy_arn --version-id v1
   ```

   An example output is as follows.

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "s3:GetObject",
               "Resource": "arn:aws:s3:::my-pod-secrets-bucket"
           }
       ]
   }
   ```

   If you created the example policy in a previous step, then your output is the same. If you created a different policy, then the *example* content is different.

1. Confirm that the Kubernetes service account is annotated with the role.

   ```
   kubectl describe serviceaccount my-service-account -n default
   ```

   An example output is as follows.

   ```
   Name:                my-service-account
   Namespace:           default
   Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role
   Image pull secrets:  <none>
   Mountable secrets:   my-service-account-token-qqjfl
   Tokens:              my-service-account-token-qqjfl
   [...]
   ```

## Next steps
<a name="_next_steps"></a>
+  [Configure Pods to use a Kubernetes service account](pod-configuration.md) 

# Configure Pods to use a Kubernetes service account
<a name="pod-configuration"></a>

If a Pod needs to access AWS services, then you must configure it to use a Kubernetes service account. The service account must be associated to an AWS Identity and Access Management (IAM) role that has permissions to access the AWS services.
+ An existing cluster. If you don’t have one, you can create one using one of the guides in [Get started with Amazon EKS](getting-started.md).
+ An existing IAM OpenID Connect (OIDC) provider for your cluster. To learn if you already have one or how to create one, see [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md).
+ An existing Kubernetes service account that’s associated with an IAM role. The service account must be annotated with the Amazon Resource Name (ARN) of the IAM role. The role must have an associated IAM policy that contains the permissions that you want your Pods to have to use AWS services. For more information about how to create the service account and role, and configure them, see [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md).
+ Version `2.12.3` or later or version `1.27.160` or later of the AWS Command Line Interface (AWS CLI) installed and configured on your device or AWS CloudShell. To check your current version, use `aws --version | cut -d / -f2 | cut -d ' ' -f1`. Package managers such as `yum`, `apt-get`, or Homebrew for macOS are often several versions behind the latest version of the AWS CLI. To install the latest version, see [Installing](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) and [Quick configuration with aws configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) in the * AWS Command Line Interface User Guide*. The AWS CLI version that is installed in AWS CloudShell might also be several versions behind the latest version. To update it, see [Installing AWS CLI to your home directory](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software) in the * AWS CloudShell User Guide*.
+ The `kubectl` command line tool is installed on your device or AWS CloudShell. The version can be the same as or up to one minor version earlier or later than the Kubernetes version of your cluster. For example, if your cluster version is `1.29`, you can use `kubectl` version `1.28`, `1.29`, or `1.30` with it. To install or upgrade `kubectl`, see [Set up `kubectl` and `eksctl`](install-kubectl.md).
+ An existing `kubectl` `config` file that contains your cluster configuration. To create a `kubectl` `config` file, see [Connect kubectl to an EKS cluster by creating a kubeconfig file](create-kubeconfig.md).

  1. Use the following command to create a deployment manifest that you can deploy a Pod to confirm configuration with. Replace the example values with your own values.

     ```
     cat >my-deployment.yaml <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: my-app
     spec:
       selector:
         matchLabels:
           app: my-app
       template:
         metadata:
           labels:
             app: my-app
         spec:
           serviceAccountName: my-service-account
           containers:
           - name: my-app
             image: public.ecr.aws/nginx/nginx:X.XX
     EOF
     ```

  1. Deploy the manifest to your cluster.

     ```
     kubectl apply -f my-deployment.yaml
     ```

  1. Confirm that the required environment variables exist for your Pod.

     1. View the Pods that were deployed with the deployment in the previous step.

        ```
        kubectl get pods | grep my-app
        ```

        An example output is as follows.

        ```
        my-app-6f4dfff6cb-76cv9   1/1     Running   0          3m28s
        ```

     1. View the ARN of the IAM role that the Pod is using.

        ```
        kubectl describe pod my-app-6f4dfff6cb-76cv9 | grep AWS_ROLE_ARN:
        ```

        An example output is as follows.

        ```
        AWS_ROLE_ARN:                 arn:aws:iam::111122223333:role/my-role
        ```

        The role ARN must match the role ARN that you annotated the existing service account with. For more about annotating the service account, see [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md).

     1. Confirm that the Pod has a web identity token file mount.

        ```
        kubectl describe pod my-app-6f4dfff6cb-76cv9 | grep AWS_WEB_IDENTITY_TOKEN_FILE:
        ```

        An example output is as follows.

        ```
        AWS_WEB_IDENTITY_TOKEN_FILE:  /var/run/secrets/eks.amazonaws.com/serviceaccount/token
        ```

        The `kubelet` requests and stores the token on behalf of the Pod. By default, the `kubelet` refreshes the token if the token is older than 80 percent of its total time to live or older than 24 hours. You can modify the expiration duration for any account other than the default service account by using the settings in your Pod spec. For more information, see [Service Account Token Volume Projection](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection) in the Kubernetes documentation.

        The [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook#amazon-eks-pod-identity-webhook) on the cluster watches for Pods that use a service account with the following annotation:

        ```
        eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role
        ```

        The webhook applies the previous environment variables to those Pods. Your cluster doesn’t need to use the webhook to configure the environment variables and token file mounts. You can manually configure Pods to have these environment variables. The [supported versions of the AWS SDK](iam-roles-for-service-accounts-minimum-sdk.md) look for these environment variables first in the credential chain provider. The role credentials are used for Pods that meet this criteria.

  1. Confirm that your Pods can interact with the AWS services using the permissions that you assigned in the IAM policy attached to your role.
**Note**  
When a Pod uses AWS credentials from an IAM role that’s associated with a service account, the AWS CLI or other SDKs in the containers for that Pod use the credentials that are provided by that role. If you don’t restrict access to the credentials that are provided to the [Amazon EKS node IAM role](create-node-role.md), the Pod still has access to these credentials. For more information, see [Restrict access to the instance profile assigned to the worker node](https://aws.github.io/aws-eks-best-practices/security/docs/iam/#restrict-access-to-the-instance-profile-assigned-to-the-worker-node).

     If your Pods can’t interact with the services as you expected, complete the following steps to confirm that everything is properly configured.

     1. Confirm that your Pods use an AWS SDK version that supports assuming an IAM role through an OpenID Connect web identity token file. For more information, see [Use IRSA with the AWS SDK](iam-roles-for-service-accounts-minimum-sdk.md).

     1. Confirm that the deployment is using the service account.

        ```
        kubectl describe deployment my-app | grep "Service Account"
        ```

        An example output is as follows.

        ```
        Service Account:  my-service-account
        ```

     1. If your Pods still can’t access services, review the [steps](associate-service-account-role.md#irsa-confirm-role-configuration) that are described in [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md) to confirm that your role and service account are configured properly.

# Configure the AWS Security Token Service endpoint for a service account
<a name="configure-sts-endpoint"></a>

If you’re using a Kubernetes service account with [IAM roles for service accounts](iam-roles-for-service-accounts.md), then you can configure the type of AWS Security Token Service endpoint that’s used by the service account.

 AWS recommends using the regional AWS STS endpoints instead of the global endpoint. This reduces latency, provides built-in redundancy, and increases session token validity. The AWS Security Token Service must be active in the AWS Region where the Pod is running. Moreover, your application must have built-in redundancy for a different AWS Region in the event of a failure of the service in the AWS Region. For more information, see [Managing AWS STS in an AWS Region](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) in the IAM User Guide.
+ An existing cluster. If you don’t have one, you can create one using one of the guides in [Get started with Amazon EKS](getting-started.md).
+ An existing IAM OIDC provider for your cluster. For more information, see [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md).
+ An existing Kubernetes service account configured for use with the [Amazon EKS IAM for service accounts](iam-roles-for-service-accounts.md) feature.

The following examples all use the aws-node Kubernetes service account used by the [Amazon VPC CNI plugin](cni-iam-role.md). You can replace the *example values* with your own service accounts, Pods, namespaces, and other resources.

1. Select a Pod that uses a service account that you want to change the endpoint for. Determine which AWS Region that the Pod runs in. Replace *aws-node-6mfgv* with your Pod name and *kube-system* with your Pod’s namespace.

   ```
   kubectl describe pod aws-node-6mfgv -n kube-system |grep Node:
   ```

   An example output is as follows.

   ```
   ip-192-168-79-166.us-west-2/192.168.79.166
   ```

   In the previous output, the Pod is running on a node in the us-west-2 AWS Region.

1. Determine the endpoint type that the Pod’s service account is using.

   ```
   kubectl describe pod aws-node-6mfgv -n kube-system |grep AWS_STS_REGIONAL_ENDPOINTS
   ```

   An example output is as follows.

   ```
   AWS_STS_REGIONAL_ENDPOINTS: regional
   ```

   If the current endpoint is global, then `global` is returned in the output. If no output is returned, then the default endpoint type is in use and has not been overridden.

1. If your cluster or platform version are the same or later than those listed in the table, then you can change the endpoint type used by your service account from the default type to a different type with one of the following commands. Replace *aws-node* with the name of your service account and *kube-system* with the namespace for your service account.
   + If your default or current endpoint type is global and you want to change it to regional:

     ```
     kubectl annotate serviceaccount -n kube-system aws-node eks.amazonaws.com/sts-regional-endpoints=true
     ```

     If you’re using [IAM roles for service accounts](iam-roles-for-service-accounts.md) to generate pre-signed S3 URLs in your application running in Pods' containers, the format of the URL for regional endpoints is similar to the following example:

     ```
     https://bucket.s3.us-west-2.amazonaws.com/path?...&X-Amz-Credential=your-access-key-id/date/us-west-2/s3/aws4_request&...
     ```
   + If your default or current endpoint type is regional and you want to change it to global:

     ```
     kubectl annotate serviceaccount -n kube-system aws-node eks.amazonaws.com/sts-regional-endpoints=false
     ```

     If your application is explicitly making requests to AWS STS global endpoints and you don’t override the default behavior of using regional endpoints in Amazon EKS clusters, then requests will fail with an error. For more information, see [Pod containers receive the following error: `An error occurred (SignatureDoesNotMatch) when calling the GetCallerIdentity operation: Credential should be scoped to a valid region`](security-iam-troubleshoot.md#security-iam-troubleshoot-wrong-sts-endpoint).

     If you’re using [IAM roles for service accounts](iam-roles-for-service-accounts.md) to generate pre-signed S3 URLs in your application running in Pods' containers, the format of the URL for global endpoints is similar to the following example:

     ```
     https://bucket.s3.amazonaws.com/path?...&X-Amz-Credential=your-access-key-id/date/us-west-2/s3/aws4_request&...
     ```

   If you have automation that expects the pre-signed URL in a certain format or if your application or downstream dependencies that use pre-signed URLs have expectations for the AWS Region targeted, then make the necessary changes to use the appropriate AWS STS endpoint.

1. Delete and re-create any existing Pods that are associated with the service account to apply the credential environment variables. The mutating web hook doesn’t apply them to Pods that are already running. You can replace *Pods*, *kube-system*, and *-l k8s-app=aws-node* with the information for the Pods that you set your annotation for.

   ```
   kubectl delete Pods -n kube-system -l k8s-app=aws-node
   ```

1. Confirm that the all Pods restarted.

   ```
   kubectl get Pods -n kube-system -l k8s-app=aws-node
   ```

1. View the environment variables for one of the Pods. Verify that the `AWS_STS_REGIONAL_ENDPOINTS` value is what you set it to in a previous step.

   ```
   kubectl describe pod aws-node-kzbtr -n kube-system |grep AWS_STS_REGIONAL_ENDPOINTS
   ```

   An example output is as follows.

   ```
   AWS_STS_REGIONAL_ENDPOINTS=regional
   ```

# Authenticate to another account with IRSA
<a name="cross-account-access"></a>

You can configure cross-account IAM permissions either by creating an identity provider from another account’s cluster or by using chained `AssumeRole` operations. In the following examples, *Account A* owns an Amazon EKS cluster that supports IAM roles for service accounts. Pods that are running on that cluster must assume IAM permissions from *Account B*.
+  **Option 1** is simpler but requires Account B to create and manage an OIDC identity provider for Account A’s cluster.
+  **Option 2** keeps OIDC management in Account A but requires role chaining through two `AssumeRole` calls.

## Option 1: Create an identity provider from another account’s cluster
<a name="_option_1_create_an_identity_provider_from_another_accounts_cluster"></a>

In this example, Account A provides Account B with the OpenID Connect (OIDC) issuer URL from their cluster. Account B follows the instructions in [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md) and [Assign IAM roles to Kubernetes service accounts](associate-service-account-role.md) using the OIDC issuer URL from Account A’s cluster. Then, a cluster administrator annotates the service account in Account A’s cluster to use the role from Account B (*444455556666*).

```
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::444455556666:role/account-b-role
```

## Option 2: Use chained `AssumeRole` operations
<a name="_option_2_use_chained_assumerole_operations"></a>

In this approach, each account creates an IAM role. Account B’s role trusts Account A, and Account A’s role uses OIDC federation to get credentials from the cluster. The Pod then chains the two roles together using AWS CLI profiles.

### Step 1: Create the target role in Account B
<a name="_step_1_create_the_target_role_in_account_b"></a>

Account B (*444455556666*) creates an IAM role with the permissions that Pods in Account A’s cluster need. Account B attaches the desired permission policy to this role, then adds the following trust policy.

 **Trust policy for Account B’s role** — This policy allows Account A’s specific IRSA role to assume this role.

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}
```

**Important**  
For least privilege, replace the `Principal` ARN with the specific role ARN from Account A instead of using the account root (`arn:aws:iam::111122223333:root`). Using the account root allows *any* IAM principal in Account A to assume this role.

### Step 2: Create the IRSA role in Account A
<a name="_step_2_create_the_irsa_role_in_account_a"></a>

Account A (*111122223333*) creates a role with a trust policy that gets credentials from the identity provider created with the cluster’s OIDC issuer address.

 **Trust policy for Account A’s role (OIDC federation)** — This policy allows the EKS cluster’s OIDC provider to issue credentials for this role.

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}
```

**Important**  
For least privilege, add a `StringEquals` condition for the `sub` claim to restrict this role to a specific Kubernetes service account. Without a `sub` condition, any service account in the cluster can assume this role. The `sub` value uses the format `system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT_NAME `. For example, to restrict to a service account named `my-service-account` in the `default` namespace:  

```
"oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:default:my-service-account"
```

### Step 3: Attach the AssumeRole permission to Account A’s role
<a name="_step_3_attach_the_assumerole_permission_to_account_as_role"></a>

Account A attaches a permission policy to the role created in Step 2. This policy allows the role to assume Account B’s role.

 **Permission policy for Account A’s role** — This policy grants `sts:AssumeRole` on Account B’s target role.

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::444455556666:role/account-b-role"
        }
    ]
}
```

### Step 4: Configure the Pod to chain roles
<a name="_step_4_configure_the_pod_to_chain_roles"></a>

The application code for Pods to assume Account B’s role uses two profiles: `account_b_role` and `account_a_role`. The `account_b_role` profile uses the `account_a_role` profile as its source. For the AWS CLI, the `~/.aws/config` file is similar to the following.

```
[profile account_b_role]
source_profile = account_a_role
role_arn=arn:aws:iam::444455556666:role/account-b-role

[profile account_a_role]
web_identity_token_file = /var/run/secrets/eks.amazonaws.com/serviceaccount/token
role_arn=arn:aws:iam::111122223333:role/account-a-role
```

To specify chained profiles for other AWS SDKs, consult the documentation for the SDK that you’re using. For more information, see [Tools to Build on AWS](https://aws.amazon.com/developer/tools/).

# Use IRSA with the AWS SDK
<a name="iam-roles-for-service-accounts-minimum-sdk"></a>

**Using the credentials**  
To use the credentials from IAM roles for service accounts (IRSA), your code can use any AWS SDK to create a client for an AWS service with an SDK, and by default the SDK searches in a chain of locations for AWS Identity and Access Management credentials to use. The IAM roles for service accounts credentials will be used if you don’t specify a credential provider when you create the client or otherwise initialized the SDK.

This works because IAM roles for service accounts have been added as a step in the default credential chain. If your workloads currently use credentials that are earlier in the chain of credentials, those credentials will continue to be used even if you configure an IAM roles for service accounts for the same workload.

The SDK automatically exchanges the service account OIDC token for temporary credentials from AWS Security Token Service by using the `AssumeRoleWithWebIdentity` action. Amazon EKS and this SDK action continue to rotate the temporary credentials by renewing them before they expire.

When using [IAM roles for service accounts](iam-roles-for-service-accounts.md), the containers in your Pods must use an AWS SDK version that supports assuming an IAM role through an OpenID Connect web identity token file. Make sure that you’re using the following versions, or later, for your AWS SDK:
+ Java (Version 2) – [2.10.11](https://github.com/aws/aws-sdk-java-v2/releases/tag/2.10.11) 
+ Java – [1.12.782](https://github.com/aws/aws-sdk-java/releases/tag/1.12.782) 
+  AWS SDK for Go v1 – [1.23.13](https://github.com/aws/aws-sdk-go/releases/tag/v1.23.13) 
+  AWS SDK for Go v2 – All versions support
+ Python (Boto3) – [1.9.220](https://github.com/boto/boto3/releases/tag/1.9.220) 
+ Python (botocore) – [1.12.200](https://github.com/boto/botocore/releases/tag/1.12.200) 
+  AWS CLI – [1.16.232](https://github.com/aws/aws-cli/releases/tag/1.16.232) 
+ Node – [2.525.0](https://github.com/aws/aws-sdk-js/releases/tag/v2.525.0) and [3.27.0](https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.27.0) 
+ Ruby – [3.58.0](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-core/CHANGELOG.md#3580-2019-07-01) 
+ C\$1\$1 – [1.7.174](https://github.com/aws/aws-sdk-cpp/releases/tag/1.7.174) 
+ .NET – [3.3.659.1](https://github.com/aws/aws-sdk-net/releases/tag/3.3.659.1) – You must also include `AWSSDK.SecurityToken`.
+ PHP – [3.110.7](https://github.com/aws/aws-sdk-php/releases/tag/3.110.7) 

Many popular Kubernetes add-ons, such as the [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler), the [Route internet traffic with AWS Load Balancer Controller](aws-load-balancer-controller.md), and the [Amazon VPC CNI plugin for Kubernetes](cni-iam-role.md) support IAM roles for service accounts.

To ensure that you’re using a supported SDK, follow the installation instructions for your preferred SDK at [Tools to Build on AWS](https://aws.amazon.com/tools/) when you build your containers.

## Considerations
<a name="_considerations"></a>

### Java
<a name="_java"></a>

When using Java, you *must* include the `sts` module on the classpath. For more information, see [WebIdentityTokenFileCredentialsProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/WebIdentityTokenFileCredentialsProvider.html) in the Java SDK docs.

# Fetch signing keys to validate OIDC tokens
<a name="irsa-fetch-keys"></a>

Kubernetes issues a `ProjectedServiceAccountToken` to each Kubernetes Service Account. This token is an OIDC token, which is further a type of JSON web token (JWT). Amazon EKS hosts a public OIDC endpoint for each cluster that contains the signing keys for the token so external systems can validate it.

To validate a `ProjectedServiceAccountToken`, you need to fetch the OIDC public signing keys, also called the JSON Web Key Set (JWKS). Use these keys in your application to validate the token. For example, you can use the [PyJWT Python library](https://pyjwt.readthedocs.io/en/latest/) to validate tokens using these keys. For more information on the `ProjectedServiceAccountToken`, see [IAM, Kubernetes, and OpenID Connect (OIDC) background information](iam-roles-for-service-accounts.md#irsa-oidc-background).

## Prerequisites
<a name="_prerequisites"></a>
+ An existing AWS Identity and Access Management (IAM) OpenID Connect (OIDC) provider for your cluster. To determine whether you already have one, or to create one, see [Create an IAM OIDC provider for your cluster](enable-iam-roles-for-service-accounts.md).
+  ** AWS CLI** — A command line tool for working with AWS services, including Amazon EKS. For more information, see [Installing](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) in the AWS Command Line Interface User Guide. After installing the AWS CLI, we recommend that you also configure it. For more information, see [Quick configuration with aws configure](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) in the AWS Command Line Interface User Guide.

## Procedure
<a name="_procedure"></a>

1. Retrieve the OIDC URL for your Amazon EKS cluster using the AWS CLI.

   ```
   $ aws eks describe-cluster --name my-cluster --query 'cluster.identity.oidc.issuer'
   "https://oidc.eks.us-west-2.amazonaws.com/id/8EBDXXXX00BAE"
   ```

1. Retrieve the public signing key using curl, or a similar tool. The result is a [JSON Web Key Set (JWKS)](https://www.rfc-editor.org/rfc/rfc7517#section-5).
**Important**  
Amazon EKS throttles calls to the OIDC endpoint. You should cache the public signing key. Respect the `cache-control` header included in the response.
**Important**  
Amazon EKS rotates the OIDC signing key every seven days.

   ```
   $ curl https://oidc.eks.us-west-2.amazonaws.com/id/8EBDXXXX00BAE/keys
   {"keys":[{"kty":"RSA","kid":"2284XXXX4a40","use":"sig","alg":"RS256","n":"wklbXXXXMVfQ","e":"AQAB"}]}
   ```