AWS Load Balancer Controller
Introduction
This page describes how to use the AWS Load Balancer Controller as Ingress Controller in your Kubernetes cluster. The ALB controller provisions AWS Application Load Balancers for your Kubernetes Ingress resources.
Pre-requisites
First determine whether you want to use the AWS Load Balancer Controller for your Ingress. We offer several options depending on your needs: Explanation: Ingress.
Basic Ingress Configuration
A minimal ALB Ingress looks like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80Scheme Options
| Scheme | Description |
|---|---|
internet-facing | ALB is accessible from the internet |
internal | ALB is only accessible within the VPC |
This can be set via the alb.ingress.kubernetes.io/scheme annotation.
Target Type Options
| Target Type | Description |
|---|---|
ip | Routes directly to pod IPs (recommended) |
instance | Routes to node ports |
This can be set via the alb.ingress.kubernetes.io/target-type annotation.
TLS/SSL Configuration
Using ACM Certificates
The ALB controller integrates with AWS Certificate Manager (ACM) for TLS termination:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-west-1:123456789:certificate/abc-123
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
spec:
ingressClassName: alb
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80Note: this certificate is applied to the ALB and therefore shared across all Ingresses using the same ALB (e.g., via group.name annotation).
Automatic Certificate Discovery
Instead of specifying the certificate ARN, you can let ALB auto-discover certificates:
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
spec:
tls:
- hosts:
- my-app.example.comSSL Policy
Control TLS versions and ciphers:
annotations:
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06Common policies:
| Policy | Description |
|---|---|
ELBSecurityPolicy-TLS13-1-2-2021-06 | TLS 1.3 + TLS 1.2 (recommended) |
ELBSecurityPolicy-TLS-1-2-2017-01 | TLS 1.2 only |
ELBSecurityPolicy-FS-1-2-Res-2020-10 | Forward secrecy, TLS 1.2 |
URL Rewriting
As of ALB controller v2.14.1, URL rewriting with regex is supported via the transforms annotation.
Basic Path Stripping
Strip a prefix from the URL path (e.g., /api/users → /users):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-service
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/transforms.api-service: |
[
{
"type": "url-rewrite",
"urlRewriteConfig": {
"rewrites": [{
"regex": "^/api/(.*)$",
"replace": "/$1"
}]
}
}
]
spec:
ingressClassName: alb
rules:
- host: api.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80Version Prefix Rewriting
Rewrite versioned API paths (e.g., /v1/users → /users):
annotations:
alb.ingress.kubernetes.io/transforms.api-service: |
[
{
"type": "url-rewrite",
"urlRewriteConfig": {
"rewrites": [{
"regex": "^/v[0-9]+/(.*)$",
"replace": "/$1"
}]
}
}
]Redirects
Permanent Redirect (301)
Redirect all traffic to a new domain:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-old-domain
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/actions.redirect: |
{
"type": "redirect",
"redirectConfig": {
"host": "new-domain.example.com",
"path": "/#{path}",
"query": "#{query}",
"port": "443",
"protocol": "HTTPS",
"statusCode": "HTTP_301"
}
}
spec:
ingressClassName: alb
rules:
- host: old-domain.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: redirect
port:
name: use-annotationHTTP to HTTPS Redirect
Force all HTTP traffic to HTTPS:
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"Authentication
ALB supports native OIDC and Cognito authentication at the load balancer level.
OIDC Authentication
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: authenticated-app
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/auth-type: oidc
alb.ingress.kubernetes.io/auth-idp-oidc: |
{
"issuer": "https://accounts.google.com",
"authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"tokenEndpoint": "https://oauth2.googleapis.com/token",
"userInfoEndpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"secretName": "oidc-secret"
}
alb.ingress.kubernetes.io/auth-scope: "openid email profile"
alb.ingress.kubernetes.io/auth-session-cookie: AWSELBAuthSessionCookie
alb.ingress.kubernetes.io/auth-session-timeout: "3600"
spec:
ingressClassName: alb
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80The OIDC secret must contain:
apiVersion: v1
kind: Secret
metadata:
name: oidc-secret
type: Opaque
stringData:
clientId: your-client-id
clientSecret: your-client-secretIP Whitelisting
Restrict access to specific IP ranges:
annotations:
alb.ingress.kubernetes.io/inbound-cidrs: 10.0.0.0/8, 192.168.1.0/24, 203.0.113.50/32Alternatively, use security groups:
annotations:
alb.ingress.kubernetes.io/security-groups: sg-xxxx, sg-yyyy
alb.ingress.kubernetes.io/manage-backend-security-group-rules: "true"Timeouts and Health Checks
Idle Timeout
Configure the ALB idle timeout (default: 60 seconds, max: 4000 seconds):
annotations:
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=300Health Check Configuration
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /health
alb.ingress.kubernetes.io/healthcheck-port: traffic-port
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "15"
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: "5"
alb.ingress.kubernetes.io/healthy-threshold-count: "2"
alb.ingress.kubernetes.io/unhealthy-threshold-count: "2"
alb.ingress.kubernetes.io/success-codes: "200-299"Deregistration Delay
Time to wait before deregistering targets (useful for graceful shutdown):
annotations:
alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30Session Affinity (Sticky Sessions)
Enable sticky sessions (requires target-type: ip):
annotations:
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/target-group-attributes: |
stickiness.enabled=true,
stickiness.lb_cookie.duration_seconds=3600,
stickiness.type=lb_cookieGrouping Ingresses
Multiple Ingress resources can share a single ALB using the group.name annotation:
# Ingress 1
metadata:
name: app1
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: "1"
# Ingress 2
metadata:
name: app2
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: "2"This reduces costs by sharing a single ALB across multiple services.
Limitations
The AWS Load Balancer Controller does not support:
| Feature | Alternative |
|---|---|
| CORS headers | Implement in application, or use CloudFront Response Headers Policy |
| Rate limiting | Use AWS WAF Rate-Based Rules |
| Custom nginx snippets | Refactor to application logic / lambda@edge or use Traefik |
Migration from ingress-nginx
Annotation Mapping
| ingress-nginx | ALB Controller |
|---|---|
nginx.ingress.kubernetes.io/ssl-redirect: "true" | alb.ingress.kubernetes.io/ssl-redirect: "443" |
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" | alb.ingress.kubernetes.io/ssl-redirect: "443" |
nginx.ingress.kubernetes.io/rewrite-target: /$1 | alb.ingress.kubernetes.io/transforms.<svc>: [...] |
nginx.ingress.kubernetes.io/whitelist-source-range | alb.ingress.kubernetes.io/inbound-cidrs |
nginx.ingress.kubernetes.io/auth-url | alb.ingress.kubernetes.io/auth-type: oidc |
nginx.ingress.kubernetes.io/proxy-read-timeout | alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=X |
nginx.ingress.kubernetes.io/affinity: cookie | alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true |