Service Foundry
Young Gyu Kim <credemol@gmail.com>

Securing Web Apps on Kubernetes with TLS Using AWS Load Balancer Controller and Traefik

intro

Introduction

YouTube Tutorial

https://youtu.be/EW4uJ6hUIRE

In our previous guide, we explored how to secure a Kubernetes web application using TLS with AWS Certificate Manager (ACM) and the default Kubernetes Service of type LoadBalancer. However, this approach didn’t use the AWS Load Balancer Controller.

prev intro

While it worked, the default Kubernetes Service controller provisions:

  • Classic Load Balancer (CLB) for HTTP/HTTPS (now deprecated)

  • Network Load Balancer (NLB) for TCP/UDP

Although NLBs are suitable for specific use cases, Application Load Balancers (ALBs) offer advanced features such as path-based and host-based routing—making them ideal for modern web applications.

This guide walks you through installing and configuring the AWS Load Balancer Controller to provision an ALB for your Kubernetes workloads. We’ll also demonstrate how to integrate Traefik as your Ingress Controller with this setup.

What Is the AWS Load Balancer Controller?

The AWS Load Balancer Controller helps manage AWS Elastic Load Balancers for Kubernetes workloads. It automatically creates and manages ALBs or NLBs based on your Kubernetes Ingress or Service resources.

This lets you expose your applications through a single DNS endpoint managed by AWS.

Step-by-Step Setup Overview

  1. Install the AWS Load Balancer Controller

  2. Install the Traefik Ingress Controller using NodePort

  3. Configure an ALB Ingress resource for Traefik

  4. Update Route 53 DNS records

  5. Test HTTPS access to your app

Installing the AWS Load Balancer Controller

We’ll use Helm to install the controller. First, add and update the EKS Helm chart repository:

$ helm repo add eks https://aws.github.io/eks-charts
$ helm repo update eks

Then save the default configuration for version 1.14.1:

$ helm pull eks/aws-load-balancer-controller
$ helm show values eks/aws-load-balancer-controller > values-1.14.1.yaml

Create IAM Role Using eksctl

We need a service account with appropriate IAM permissions:

$ eksctl create iamserviceaccount \
    --cluster=$EKS_CLUSTER_NAME \
    --namespace=kube-system \
    --name=aws-load-balancer-controller \
    --attach-policy-arn arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess \
    --attach-policy-arn=arn:aws:iam::$AWS_ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --region $AWS_REGION \
    --approve

Verify the service account exists:

$ kubectl get serviceaccount -n kube-system aws-load-balancer-controller -o yaml

Configure Helm Custom Values

Use these settings in your custom values file:

serviceAccount:
  create: false
  name: aws-load-balancer-controller

clusterName: your-eks-cluster-name

Install the controller:

$ helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
    -f k8s/aws-load-balancer-controller/custom-values.yaml \
    --namespace kube-system --create-namespace --version 1.14.1

Confirm that the controller is running:

$ kubectl get deployment -n kube-system aws-load-balancer-controller

Installing Traefik with NodePort for ALB

To route traffic through an ALB, Traefik must expose its service as NodePort:

ingressRoute:
  healthcheck:
    enabled: true

ports:
  traefik:
    nodePort: 31080
    expose:
      default: true
  web:
    port: 80
    nodePort: 30080
  websecure:
    port: 443
    nodePort: 30443

service:
  type: NodePort

Install Traefik:

$ helm upgrade --install traefik traefik/traefik \
    -f k8s/alb-traefik/custom-values.yaml \
    --namespace traefik --create-namespace

Creating the ALB Ingress Resource

Define an Ingress with the right annotations to instruct the controller to create an ALB:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-alb
  namespace: traefik
  annotations:
    alb.ingress.kubernetes.io/load-balancer-name: traefik-alb
    alb.ingress.kubernetes.io/tags: "servicefoundry.org/service-name=traefik/traefik-alb,servicefoundry.org/provider=service-foundry"
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: instance
    alb.ingress.kubernetes.io/healthcheck-path: /ping
    alb.ingress.kubernetes.io/healthcheck-port: '31080'
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:aws-region:aws-account-id:certificate/certificate-arn
spec:
  ingressClassName: alb
  rules:
    - host: '*.servicefoundry.org'
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: traefik
                port:
                  number: 80

Apply the Ingress:

$ kubectl apply -f k8s/alb-traefik/traefik-alb-ingress.yaml

Verifying the ALB Setup

aws load balancer traefik alb

The ALB named traefik-alb is now created.

aws load balancer tags

Tags added in the annotations appear in the Load Balancer’s AWS console and can be used by Terraform later.

aws target groups

A target group is created automatically and linked to EC2 instances on port 30080.

aws target groups health checks

Health checks use the /ping path and port 31080 as defined in the annotations.

Updating DNS Records

Use Route 53 to map your domain (e.g., dev.servicefoundry.org) to the Load Balancer DNS name using Alias routing.

aws route53 update dns
TIP

In the next guide, we’ll show how to automate this using Terraform and tags.

Verifying HTTPS Access

Once DNS is updated, navigate to https://dev.servicefoundry.org to verify your app is accessible over HTTPS.

dev servicefoundry org

Conclusion

intro

We’ve successfully integrated the AWS Load Balancer Controller with Traefik to create an ALB that routes HTTPS traffic to our Kubernetes web application. This solution is more flexible and production-ready compared to using NLBs or CLBs, and it aligns with modern cloud-native architecture practices.

📘 View the web version: