Granting cross-account access to an Amazon EKS cluster means allowing users or services in a different AWS account to interact with your Kubernetes cluster. This is a common requirement for organizations with multiple AWS accounts for different teams, environments, or compliance reasons.
Let’s say you have an EKS cluster in AccountA and a CI/CD pipeline in AccountB that needs to deploy applications to it. Or maybe a security team in AccountC needs read-only access to audit cluster state.
Here’s how you can achieve this, focusing on the EKS control plane access and then the Kubernetes RBAC.
EKS Control Plane Access
The EKS control plane itself is an AWS resource. To grant access to it from another account, you need to configure IAM policies.
The core mechanism is an IAM role in the EKS cluster’s account (AccountA) that the principals (users or roles) in the other account (AccountB or AccountC) can assume.
-
Create an IAM Role in the EKS Cluster Account (
AccountA) This role will be trusted byAccountBand will have permissions to interact with the EKS control plane.- Create the Role: In
AccountA, go to IAM -> Roles -> Create role. - Trusted entity type: Select "AWS account".
- Another AWS account: Enter the AWS Account ID of
AccountB. - Attach Permissions Policies:
AmazonEKSClusterPolicy: This managed policy grants broad permissions to interact with EKS clusters. For stricter security, you’d create a custom inline policy.- For read-only access, you might use a custom policy like this:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "eks:DescribeCluster", "eks:ListClusters", "eks:ListNodegroups", "eks:DescribeNodegroup", "eks:ListTagsForResource" ], "Resource": "*" // Or specify your cluster ARN for better security } ] }
- Role Name: Give it a descriptive name, e.g.,
CrossAccountEKSAdminRoleorCrossAccountEKSReadOnlyRole.
- Create the Role: In
-
Grant Assume Role Permission to Principals in the Other Account (
AccountB) Now, inAccountB, you need to grant your users or roles permission to assume the role you just created inAccountA.- Create an IAM Policy in
AccountB:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::<AccountA_ID>:role/<CrossAccountEKSAdminRoleName>" } ] } - Attach this policy to the IAM users or roles in
AccountBthat need to access the EKS cluster.
- Create an IAM Policy in
-
Assume the Role and Configure
kubectlFromAccountB, a user or an assumed role can now assume theCrossAccountEKSAdminRoleinAccountA.-
Using AWS CLI:
aws sts assume-role --role-arn arn:aws:iam::<AccountA_ID>:role/<CrossAccountEKSAdminRoleName> --role-session-name "MyEKSClusterSession"This will output temporary credentials (AccessKeyId, SecretAccessKey, SessionToken). You can then set these as environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN) or use them to configure your~/.aws/credentialsfile. -
Using
aws-iam-authenticatororaws eks update-kubeconfig: Theaws eks update-kubeconfigcommand is the modern and recommended way. It handles the authentication flow for you. First, ensure your local AWS CLI is configured with credentials that havests:AssumeRolepermission to the role inAccountA. Then, run:aws eks update-kubeconfig --region <eks-cluster-region> --name <eks-cluster-name> --role-arn arn:aws:iam::<AccountA_ID>:role/<CrossAccountEKSAdminRoleName> --profile <your-profile-in-accountB>If you’re running this from within an EC2 instance or Lambda in
AccountBwith an IAM role attached that hassts:AssumeRolepermission, you might not need--profile.This command updates your
~/.kube/configfile, setting up a context that uses theaws eks update-kubeconfighelper to authenticate with the EKS control plane. When you runkubectlcommands, it will automatically callsts:AssumeRolein the background.
-
Kubernetes RBAC Access
Granting access to the EKS control plane (AWS API) is only half the story. You also need to grant permissions within the Kubernetes cluster using Kubernetes Role-Based Access Control (RBAC).
The IAM role you assumed in AccountA needs to be mapped to a Kubernetes user or group.
-
Identify the ARN of the Assumed Role When you assume the role, the ARN of the assumed role will look like:
arn:aws:sts::<AccountA_ID>:assumed-role/<CrossAccountEKSAdminRoleName>/<SessionName> -
Create a
aws-authConfigMap in the EKS Cluster (AccountA) Theaws-authConfigMap in thekube-systemnamespace is how EKS maps IAM identities to Kubernetes RBAC. You need to edit this ConfigMap.-
Get the current ConfigMap:
kubectl get configmap aws-auth -n kube-system -o yaml -
Add a mapping: In the
mapRolesormapUserssection, add an entry. For a role, it’smapRoles.Example for granting cluster-admin privileges to the assumed role:
apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - rolearn: arn:aws:sts::<AccountA_ID>:assumed-role/<CrossAccountEKSAdminRoleName>/<SessionName> username: system:node:{{EC2PrivateDNSName}} # This is for node roles, not for assumed roles. Use a distinct username. # For assumed roles, the username is derived from the ARN. # The EKS documentation recommends a format like: username: <AccountB_ID>-<CrossAccountEKSAdminRoleName> # Or a more specific identifier groups: - system:masters # This grants cluster-admin privilegesImportant: The
usernamefield is crucial. It must be unique and will be the identitykubectluses. EKS usually derives a username from the IAM role ARN. You can explicitly define it.Example for granting specific namespace access: Let’s say you want the assumed role to have
editpermissions in themy-app-nsnamespace.First, create a Kubernetes
ClusterRole(or use an existing one likeedit) and aClusterRoleBindingorRoleBinding.You’ll typically bind the Kubernetes Role to a Kubernetes User or Group. The
usernameyou defined inaws-authbecomes the Kubernetes User. You can also map IAM roles to Kubernetes Groups.Let’s map the assumed role ARN to a Kubernetes group called
cross-account-developers.In
aws-authConfigMap:data: mapRoles: | - rolearn: arn:aws:sts::<AccountA_ID>:assumed-role/<CrossAccountEKSAdminRoleName>/<SessionName> username: cross-account-developer-user # A unique username groups: - cross-account-developers # This IAM role is now part of this K8s groupCreate a
ClusterRoleBindinginAccountA’s EKS cluster:apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cross-account-dev-binding subjects: - kind: Group name: cross-account-developers # Matches the group in mapRoles apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole # Or Role for namespaced access name: edit # A built-in ClusterRole for editing resources apiGroup: rbac.authorization.k8s.ioNow, any user or role in
AccountBthat assumes theCrossAccountEKSAdminRoleand gets mapped to thecross-account-developersgroup will haveeditpermissions within the Kubernetes cluster.
-
The most surprising thing about this setup is how EKS bridges the AWS IAM world and the Kubernetes RBAC world through the aws-auth ConfigMap. It’s not just about IAM permissions; it’s about mapping those IAM identities to distinct Kubernetes users or groups that then get Kubernetes roles.
When you use aws eks update-kubeconfig, it automatically configures your kubectl context to use the aws-iam-authenticator (or its successor, the EKS credential helper) to fetch temporary AWS credentials and then use the IAM ARN to perform the sts:AssumeRole operation. The aws-auth ConfigMap in AccountA then dictates what Kubernetes permissions that assumed role gets.
The next hurdle you’ll likely face is managing secrets for cross-account access, especially if your CI/CD pipeline needs to pull images from a private ECR repository in a different account or needs credentials to access other AWS services.