# Hybrid Ingress Routing with AWS ALB and Traefik

[Traefik](https://traefik.io/) is an excellent declarative ingress controller for Kubernetes. If you don't need all the features of cloud-managed Application Load Balancers, Traefik can be a fantastic alternative.

However, there are certain limitations of Traefik on cloud platforms. It can handle the TLS/SSL layer only through Kubernetes Secret or Let's Encrypt, meaning it cannot leverage AWS ACM for resolving SSL certificates. This limitation stems from AWS ACM itself, as it can only be used with resources like ALB and CloudFront.

However, you may want to have both 1) SSL termination by ACM and 2) support for Traefik-specific features (Middleware, Circuit Breaker, etc.) all in one place. Fortunately, I have tested a system that allows you to continue using an AWS ACM-provided SSL certificate while handling ingress routing with Traefik. Here is the high-level architecture of the proposed system:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1696017948936/73cc2555-b915-47e1-83bf-cd08f9900028.png align="center")

To set up this system, you'll first need an EKS cluster with the [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/) add-on. You can bootstrap the cluster using [eksctl](https://eksctl.io/).

Once the cluster is ready, deploy Traefik in `web` mode only, disabling the `websecure` entrypoint.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template: 
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik
      containers:
      - image: docker.io/traefik:v3.0
        name: traefik
        ports:
        - name: "web"
          containerPort: 80
        args:
          - "--entrypoints.web.address=:80/tcp"
          - "--api.dashboard=false"
          - "--providers.kubernetescrd"
```

Next, create a service for the Traefik deployment/daemonset and set its type to NodePort (ALB requires the service to be of NodePort type for its backend).

```yaml
apiVersion: v1
kind: Service
metadata:
  name: traefik
spec:
  ports:
  - name: web
    nodePort: 30080
    port: 80
    protocol: TCP
    targetPort: web
  selector:
    app: traefik
  type: NodePort
```

Next, create an ALB Ingress with the appropriate annotations for ACM UUID, Name, and Class.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/backend-protocol: HTTP
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-southeast-1:0000000000:certificate/cb6cf41e-a6f4-4fd3-9aa5-44503f317420
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/load-balancer-name: my-lb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/success-codes: 200-404
    alb.ingress.kubernetes.io/target-type: instance
  name: traefik
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - backend:
          service:
            name: traefik
            port:
              name: web
        path: /*
        pathType: ImplementationSpecific
```

Once applied, an ALB will be created. You can then route any HTTPS traffic through the ALB, and ultimately, it will be routed using Traefik within your Kubernetes Cluster. A sample `IngressRoute` object would look like this:

```yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: my-apps
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`a.example.com`)
    services:
    - name: app-a
      port: 80
  - kind: Rule
    match: Host(`b.example.com`)
    services:
    - name: app-b
      port: 80
```
