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: 80

Scheme Options

SchemeDescription
internet-facingALB is accessible from the internet
internalALB is only accessible within the VPC

This can be set via the alb.ingress.kubernetes.io/scheme annotation.

Target Type Options

Target TypeDescription
ipRoutes directly to pod IPs (recommended)
instanceRoutes 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: 80

Note: 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.com

SSL Policy

Control TLS versions and ciphers:

annotations:
  alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06

Common policies:

PolicyDescription
ELBSecurityPolicy-TLS13-1-2-2021-06TLS 1.3 + TLS 1.2 (recommended)
ELBSecurityPolicy-TLS-1-2-2017-01TLS 1.2 only
ELBSecurityPolicy-FS-1-2-Res-2020-10Forward 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: 80

Version 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-annotation

HTTP 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: 80

The OIDC secret must contain:

apiVersion: v1
kind: Secret
metadata:
  name: oidc-secret
type: Opaque
stringData:
  clientId: your-client-id
  clientSecret: your-client-secret

IP 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/32

Alternatively, 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=300

Health 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=30

Session 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_cookie

Grouping 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:

FeatureAlternative
CORS headersImplement in application, or use CloudFront Response Headers Policy
Rate limitingUse AWS WAF Rate-Based Rules
Custom nginx snippetsRefactor to application logic / lambda@edge or use Traefik

Migration from ingress-nginx

Annotation Mapping

ingress-nginxALB 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: /$1alb.ingress.kubernetes.io/transforms.<svc>: [...]
nginx.ingress.kubernetes.io/whitelist-source-rangealb.ingress.kubernetes.io/inbound-cidrs
nginx.ingress.kubernetes.io/auth-urlalb.ingress.kubernetes.io/auth-type: oidc
nginx.ingress.kubernetes.io/proxy-read-timeoutalb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=X
nginx.ingress.kubernetes.io/affinity: cookiealb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true

Further Reading

Last updated on