The AWS Load Balancer Controller is a Kubernetes controller that manages Elastic Load Balancers for Amazon EKS clusters. It provides a native way to expose Kubernetes services to external traffic by automatically provisioning and configuring AWS Application Load Balancers (ALB) and Network Load Balancers (NLB) based on Kubernetes Ingress and Service resources.
Understanding the AWS Load Balancer Controller
The AWS Load Balancer Controller operates by watching for Kubernetes Ingress and Service resources, then automatically creating and managing corresponding AWS load balancer infrastructure. When you create an Ingress resource, the controller provisions an ALB; when you create a Service of type LoadBalancer with appropriate annotations, it can provision either an ALB or NLB.
Key Components:
- Application Load Balancer (ALB): Layer 7 load balancer for HTTP/HTTPS traffic with advanced routing capabilities
- Network Load Balancer (NLB): Layer 4 load balancer for high-performance TCP/UDP traffic
- Target Groups: AWS resources that route requests to registered targets
- Listeners: Components that check for connection requests on specified ports
- Rules: Define how traffic is routed based on conditions
How It Works
The controller follows a specific workflow when managing load balancers:
- Monitoring: The controller watches for Ingress and Service events from the Kubernetes API server
- Resource Creation: When it finds resources that satisfy its requirements, it begins creating AWS resources
- Load Balancer Provisioning: An ALB or NLB is created in AWS based on the resource type and annotations
- Target Group Management: Target groups are created for each unique Kubernetes service
- Listener Configuration: Listeners are created for specified ports with appropriate certificates
- Rule Creation: Rules are established for path-based routing to correct services
The controller supports two traffic modes:
- Instance Mode: Traffic flows from ALB to Kubernetes nodes via NodePort services
- IP Mode: Traffic flows directly from ALB to Kubernetes pods (requires compatible CNI)
Prerequisites and Setup Requirements
Before installing the AWS Load Balancer Controller, ensure you have:
- AWS CLI v2.18.10 or higher
- eksctl v0.193.0 or higher
- EKS Cluster v1.30 or higher
- Pod Identity Agent v1.3.2-eksbuild.2 or higher
- Amazon VPC CNI plugin
- kubectl v1.31 or higher
- Helm v3.16.2 or higher
Sequence for Installing AWS Load Balancer Controller with Best Practices
1. OIDC Identity Provider
- Enables secure trust between Kubernetes service accounts and AWS IAM roles.
- Needed so you can use IRSA (IAM Roles for Service Accounts).
2. IAM Policy
- Write or download the official AWS Load Balancer Controller policy (JSON file).
- This policy defines what permissions the controller gets (e.g., create/manage load balancers, security groups, etc.).
3. IAM Role
- Create an IAM role with the trust policy for the OIDC provider (so only your specific K8s service account can assume it).
- Attach the policy from step 2 to this role.
4. Kubernetes Service Account (linked to IAM Role)
- Create (or update) a Kubernetes service account (e.g.,
aws-load-balancer-controller
inkube-system
namespace). - Annotate this service account with the IAM Role ARN from step 3.
5. Install AWS Load Balancer Controller
- Install via Helm (recommended), specifying that it should use your service account.
- Controller pods will automatically assume the right IAM role, get temporary AWS credentials, and have the required permissions.
IAM Permissions Configuration
The controller requires specific IAM permissions to manage AWS resources. You have two options for configuring these permissions:
Option A: IAM Roles for Service Accounts (IRSA) – Recommended
First, create an IAM OIDC provider for your cluster:
eksctl utils associate-iam-oidc-provider \
--region <region-code> \
--cluster <your-cluster-name> \
--approve
Download the appropriate IAM policy based on your region:
bash# For standard AWS regions
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.13.2/docs/install/iam_policy.json
# For US Gov Cloud regions
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.13.2/docs/install/iam_policy_us-gov.json
# For China regions
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.13.2/docs/install/iam_policy_cn.json
Create the IAM policy:
bashaws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam-policy.json
Create the IAM role and service account:
eksctl create iamserviceaccount \
--cluster=<cluster-name> \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::<AWS_ACCOUNT_ID>:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--region <region-code> \
--approve
Option B: Attach IAM Policies to Worker Nodes
If not using IRSA, attach the IAM policy directly to your worker node roles. However, this approach is less secure and not recommended for production environments.
Installation Methods
Method 1: Helm Installation (Recommended)
Add the EKS Helm repository:
bashhelm repo add eks https://aws.github.io/eks-charts
helm repo update eks
Install the controller:
bashhelm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<cluster-name> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--version 1.13.0
Method 2: YAML Manifests
Install cert-manager first:
bashkubectl apply --validate=false -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.3/cert-manager.yaml
Download and apply the controller manifest:
bashwget https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.13.2/v2_13_2_full.yaml
Edit the YAML file to set your cluster name:
textapiVersion: apps/v1
kind: Deployment
metadata:
name: aws-load-balancer-controller
namespace: kube-system
spec:
template:
spec:
containers:
- args:
- --cluster-name=<your-cluster-name>
Apply the manifest:
bashkubectl apply -f v2_13_2_full.yaml
Verification and Troubleshooting
Verify the installation:
bashkubectl get deployment -n kube-system aws-load-balancer-controller
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
Check the controller version:
bashkubectl get deploy aws-load-balancer-controller -n=kube-system -o yaml | grep image:
Verify Custom Resource Definitions:
bashkubectl get crds | grep -iE "elbv2"
kubectl get ingressclass
Configuring Application Load Balancer (ALB) with Ingress
Basic ALB Ingress Configuration
Create a basic Ingress resource for ALB:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/load-balancer-name: example-alb
spec:
ingressClassName: alb
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Advanced ALB Configuration with Multiple Services
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-service-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /health
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30'
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
alb.ingress.kubernetes.io/healthy-threshold-count: '2'
alb.ingress.kubernetes.io/unhealthy-threshold-count: '3'
spec:
ingressClassName: alb
rules:
- host: api.example.com
http:
paths:
- path: /api/v1
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /api/v2
pathType: Prefix
backend:
service:
name: api-v2-service
port:
number: 8080
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Configuring Network Load Balancer (NLB) with Services
Basic NLB Service Configuration
textapiVersion: v1
kind: Service
metadata:
name: nlb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
type: LoadBalancer
selector:
app: example-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
Advanced NLB Configuration with Security Groups
textapiVersion: v1
kind: Service
metadata:
name: advanced-nlb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-12345678
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: '2'
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: '10'
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: '2'
service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: preserve_client_ip.enabled=true
spec:
type: LoadBalancer
selector:
app: example-app
ports:
- port: 443
targetPort: 8443
protocol: TCP
name: https
- port: 80
targetPort: 8080
protocol: TCP
name: http
SSL/HTTPS Configuration
SSL Termination at ALB
Configure HTTPS with SSL certificates:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: https-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:region:account:certificate/cert-id
alb.ingress.kubernetes.io/ssl-redirect: '443'
spec:
ingressClassName: alb
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 80
Multiple SSL Certificates
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-cert-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: |
arn:aws:acm:region:account:certificate/cert-id-1,
arn:aws:acm:region:account:certificate/cert-id-2
spec:
ingressClassName: alb
rules:
- host: app1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- host: app2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
DNS Configuration with Route 53
To configure DNS routing to your load balancer, create Route 53 alias records:
- Create an Alias Record: In Route 53, create an alias record that points to your ALB or NLB
- Configure the Record: Set the record type to A (for IPv4) or AAAA (for IPv6)
- Select the Load Balancer: Choose your load balancer from the dropdown list
- Set Routing Policy: Configure appropriate routing policies (simple, weighted, latency-based, etc.)
Example Route 53 configuration:
- Record Name: api.example.com
- Record Type: A – IPv4 address
- Alias: Yes
- Route Traffic To: Alias to Application Load Balancer
- Region: Your ALB region
- Load Balancer: Select your ALB from the list
Advanced Routing and Traffic Management
Weighted Routing for Blue/Green Deployments
The AWS Load Balancer Controller supports advanced traffic splitting for blue/green deployments:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blue-green-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/actions.weighted-routing: |
{
"type": "forward",
"forwardConfig": {
"targetGroups": [
{
"serviceName": "blue-service",
"servicePort": 80,
"weight": 80
},
{
"serviceName": "green-service",
"servicePort": 80,
"weight": 20
}
]
}
}
spec:
ingressClassName: alb
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: weighted-routing
port:
name: use-annotation
Header-Based Routing
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: header-routing-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/conditions.api-v1: |
[{"field":"http-header","httpHeaderConfig":{"httpHeaderName":"X-API-Version","values":["v1"]}}]
alb.ingress.kubernetes.io/conditions.api-v2: |
[{"field":"http-header","httpHeaderConfig":{"httpHeaderName":"X-API-Version","values":["v2"]}}]
spec:
ingressClassName: alb
rules:
- host: api.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-v1
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-v2
port:
number: 80
Target Group Bindings
Target Group Binding allows you to expose pods using existing ALB or NLB target groups:
textapiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: example-tgb
namespace: default
spec:
serviceRef:
name: example-service
port: 80
targetGroupARN: arn:aws:elasticloadbalancing:region:account:targetgroup/example-tg/1234567890abcdef
targetType: ip
nodeSelector:
matchLabels:
kubernetes.io/arch: amd64
Security Best Practices
Security Group Management
The controller supports both frontend and backend security groups:
Frontend Security Groups control access to load balancers:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/security-groups: sg-frontend-12345678
alb.ingress.kubernetes.io/inbound-cidrs: 10.0.0.0/8,192.168.0.0/16
spec:
ingressClassName: alb
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 80
Backend Security Groups control load balancer to target communication:
textapiVersion: v1
kind: Service
metadata:
name: secure-nlb-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-backend-87654321
spec:
type: LoadBalancer
selector:
app: secure-app
ports:
- port: 443
targetPort: 8443
protocol: TCP
WAF Integration
Integrate AWS WAF with ALB for additional security:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: waf-protected-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/wafv2-acl-arn: arn:aws:wafv2:region:account:regional/webacl/example-waf/12345678-1234-1234-1234-123456789012
spec:
ingressClassName: alb
rules:
- host: protected.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: protected-service
port:
number: 80
Monitoring and Logging
Access Logs Configuration
Enable ALB access logs for monitoring and troubleshooting:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: logged-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/load-balancer-attributes: |
access_logs.s3.enabled=true,
access_logs.s3.bucket=my-access-logs-bucket,
access_logs.s3.prefix=alb-logs
spec:
ingressClassName: alb
rules:
- host: monitored.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: monitored-service
port:
number: 80
CloudWatch Metrics
Monitor key metrics:
- RequestCount: Number of requests processed
- TargetResponseTime: Response time from targets
- HTTPCode_Target_2XX_Count: Successful responses
- HTTPCode_Target_4XX_Count: Client errors
- HTTPCode_Target_5XX_Count: Server errors
- HealthyHostCount: Number of healthy targets
- UnHealthyHostCount: Number of unhealthy targets
Managing Multiple Load Balancers
IngressClass Parameters
Create custom IngressClass configurations for different environments:
textapiVersion: elbv2.k8s.aws/v1beta1
kind: IngressClassParams
metadata:
name: dev-class-params
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: dev
scheme: internet-facing
ipAddressType: ipv4
loadBalancerAttributes:
- key: deletion_protection.enabled
value: "true"
- key: idle_timeout.timeout_seconds
value: "120"
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: dev-alb
spec:
controller: ingress.k8s.aws/alb
parameters:
apiGroup: elbv2.k8s.aws
kind: IngressClassParams
name: dev-class-params
Ingress Grouping
Group multiple Ingress resources to share a single ALB:
textapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app1-ingress
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: '10'
spec:
ingressClassName: alb
rules:
- host: app1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app2-ingress
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: '20'
spec:
ingressClassName: alb
rules:
- host: app2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
Troubleshooting Guide
Common Issues and Solutions
1. Controller Not Installing
- Verify IAM permissions are correctly configured
- Check that OIDC provider is associated with the cluster
- Ensure service account has proper annotations
2. Load Balancer Not Created
- Check controller logs:
kubectl logs -n kube-system deployment/aws-load-balancer-controller
- Verify subnet tags are correct
- Ensure security groups allow necessary traffic
3. Health Check Failures
- Verify health check path is accessible
- Check target group health check configuration
- Ensure pods are running and ready
4. SSL Certificate Issues
- Verify certificate ARN is correct and in the same region
- Check certificate validation status in ACM
- Ensure certificate covers all hostnames
Debugging Commands
bash# Check controller status
kubectl get deployment -n kube-system aws-load-balancer-controller
# View controller logs
kubectl logs -n kube-system deployment/aws-load-balancer-controller
# Check Ingress status
kubectl describe ingress <ingress-name>
# View target group bindings
kubectl get targetgroupbindings -n <namespace> -o wide
# Check service annotations
kubectl describe service <service-name>
Version Compatibility
Always use the latest compatible version of the controller. Check the compatibility matrix:
- EKS 1.21+ requires AWS Load Balancer Controller 2.4.x+
- Kubernetes 1.22+ requires controller versions that support
networking.k8s.io/v1
API
Real-World Use Cases
E-commerce Platform
text# Frontend ALB for web traffic
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ecommerce-web
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:region:account:certificate/web-cert
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-redirect: '443'
alb.ingress.kubernetes.io/wafv2-acl-arn: arn:aws:wafv2:region:account:regional/webacl/ecommerce-waf/12345
spec:
ingressClassName: alb
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
---
# Internal NLB for database connections
apiVersion: v1
kind: Service
metadata:
name: database-nlb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internal
service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-database-access
spec:
type: LoadBalancer
selector:
app: database-proxy
ports:
- port: 5432
targetPort: 5432
protocol: TCP
Microservices Architecture
text# API Gateway ALB with path-based routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: microservices-gateway
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /health
alb.ingress.kubernetes.io/load-balancer-attributes: |
routing.http2.enabled=true,
idle_timeout.timeout_seconds=60
spec:
ingressClassName: alb
rules:
- host: api.company.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
- path: /payments
pathType: Prefix
backend:
service:
name: payment-service
port:
number: 8080
- path: /inventory
pathType: Prefix
backend:
service:
name: inventory-service
port:
number: 8080
Summary
The AWS Load Balancer Controller provides a powerful, native way to manage load balancers in Amazon EKS. Key benefits include:
- Automatic Management: Automatically provisions and configures AWS load balancers based on Kubernetes resources
- Advanced Features: Supports SSL termination, WAF integration, and advanced routing capabilities
- Cost Optimization: Enables sharing of load balancers across multiple services
- Security: Provides fine-grained security group management and integration with AWS security services
- Monitoring: Integrates with CloudWatch for comprehensive monitoring and logging
The controller supports both ALB for Layer 7 traffic and NLB for Layer 4 traffic, with extensive customization options through annotations. Proper IAM configuration, security group management, and monitoring are essential for production deployments.
Frequently Asked Questions
Q: Can the AWS Load Balancer Controller work with Classic Load Balancers?
A: No, the AWS Load Balancer Controller only supports Application Load Balancers (ALB) and Network Load Balancers (NLB). Classic Load Balancers are managed by the legacy AWS cloud controller manager.
Q: How do I migrate from the ALB Ingress Controller to the AWS Load Balancer Controller?
A: Follow the official migration guide, which involves uninstalling the old controller, updating CRDs, and installing the new controller. Existing load balancers will be preserved during the migration.
Q: Can I use the same load balancer for multiple Ingress resources?
A: Yes, use the alb.ingress.kubernetes.io/group.name
annotation to group multiple Ingress resources that should share the same ALB.
Q: What’s the difference between Instance mode and IP mode?
A: Instance mode routes traffic through NodePort services to worker nodes, while IP mode routes traffic directly to pod IPs. IP mode requires a compatible CNI plugin and is generally more efficient.
Q: How do I handle SSL certificates?
A: Use AWS Certificate Manager (ACM) to provision certificates and reference them in your Ingress annotations using the alb.ingress.kubernetes.io/certificate-arn
annotation.
Q: Can I use the controller with private subnets?
A: Yes, set the scheme to internal
using the alb.ingress.kubernetes.io/scheme: internal
annotation for internal load balancers.
Q: How do I troubleshoot load balancer creation issues?
A: Check controller logs, verify IAM permissions, ensure proper subnet tagging, and validate security group configurations. The controller logs provide detailed information about any issues encountered during resource creation.
Q: What happens to my load balancers if I delete the Ingress resource?
A: The controller automatically deletes the associated AWS load balancer resources when you delete the corresponding Kubernetes Ingress or Service resource.
Absolutely! IAM Roles for Service Accounts (IRSA) is the AWS-recommended way to securely give Kubernetes pods permissions to call AWS APIs—without using long-lived static credentials.
Creating an IAM policy, an IAM role, and connecting it to your EKS service account using IRSA for the AWS Load Balancer Controller.
1. Why Do This?
- The AWS Load Balancer Controller running inside your EKS cluster needs AWS permissions to create ALBs/NLBs, manage security groups, etc.
- Using IRSA, we “link” a Kubernetes service account with an IAM role that has the needed permissions.
- Result: The controller pod automatically gets temporary AWS credentials for that IAM role.
2. Steps Overview
- Create an IAM Policy (permissions for the controller)
- Create an IAM Role with a trust policy for EKS
- Create a Kubernetes Service Account and annotate it with the IAM role ARN
- Install the AWS Load Balancer Controller using that service account
3. Step-by-Step Guide
A. Create the IAM Policy
Save this policy to a file (e.g., aws-load-balancer-controller-policy.json
).
(You can copy the policy from here in AWS docs or use the one in the previous answer.)
Command:
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://aws-load-balancer-controller-policy.json
Code language: JavaScript (javascript)
Copy the Policy ARN from the output (e.g., arn:aws:iam::123456789012:policy/AWSLoadBalancerControllerIAMPolicy
).
B. Create an IAM Role for Service Account (using eksctl is easiest)
Recommended: Use eksctl
.
eksctl create iamserviceaccount \
--cluster <your-cluster-name> \
--namespace kube-system \
--name aws-load-balancer-controller \
--attach-policy-arn arn:aws:iam::<your-account-id>:policy/AWSLoadBalancerControllerIAMPolicy \
--approve
Code language: HTML, XML (xml)
--namespace kube-system
is where you’ll install the controller (can be different if you use a separate namespace).- This will create an IAM role and a Kubernetes service account named
aws-load-balancer-controller
in thekube-system
namespace, annotated to use that role.
Don’t want to use eksctl
?
Do it manually:
- Create IAM role with this trust policy (replace
<OIDC_PROVIDER_URL>
and<YOUR_ACCOUNT_ID>
):{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<YOUR_ACCOUNT_ID>:oidc-provider/<OIDC_PROVIDER_URL>" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "<OIDC_PROVIDER_URL>:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller" } } } ] }
- Attach the IAM policy from step A to this role.
- Annotate your K8s service account:
kubectl annotate serviceaccount -n kube-system aws-load-balancer-controller \ eks.amazonaws.com/role-arn=arn:aws:iam::<your-account-id>:role/<your-role-name>
C. Install the AWS Load Balancer Controller Using That Service Account
When you install via Helm, set:
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
Code language: JavaScript (javascript)
This tells Helm to use your existing, IRSA-enabled service account.
Summary Table
Step | What You Do | AWS CLI / Tool |
---|---|---|
Create policy | Write permissions for controller | aws iam create-policy |
Create IAM role | Trust OIDC from EKS, allow K8s ServiceAccount | eksctl or AWS console/CLI |
Attach policy | Attach policy to role | aws iam attach-role-policy |
Annotate SvcAcct | Link K8s service account to role | eksctl or kubectl annotate |
Install controller | Use that service account | Helm |
Helpful Links
- Official AWS Docs: IRSA for AWS Load Balancer Controller
- Full IAM Policy Example
- EKS OIDC Provider Setup
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND