Setting up Ingress on EKS with TLS Certificate from ACM
The scenario is when you want to terminate SSL at Elastic Load Balancer hosted in EKS.
There is an article from AWS explaining how to achieve this using Kubernetes Service. But Services on EKS create Classic Load Balancer instead of Application Load Balancer which is created if you use Ingress.
Note: Application Load Balancer is more flexible than Classic one but this is not the subject of this article.
For those who just want to see the code, GitHub repository is here.
Prerequisites
To do this, please make sure you have all other things setup such as having a domain set up on Route53 and a certificate requested from ACM. And make sure you have already had AWS Load Balancer controller set up in your EKS cluster.
You can check if you have already set up AWS Load Balancer by running the command:
kubectl get deployment -n kube-system aws-load-balancer-controller
If you don't it set up, then follow this guide to create AWS Load Balancer Controller.
Process
Once all the prerequisites are in place, create a file called deployment.yaml with the content below:
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-deployment
spec:
replicas: 2
selector:
matchLabels:
app: echo-pod
template:
metadata:
labels:
app: echo-pod
spec:
containers:
- name: echoheaders
image: k8s.gcr.io/echoserver:1.10
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
Then, run
kubectl apply -f deployment.yaml
Now, the pods should be up and running
kubectl get pods -l app=echo-pod
Next, create a service with a file called service.yaml. Note that we are using NodePort instead of LoadBalancer type.
apiVersion: v1
kind: Service
metadata:
labels:
app: echo-pod
app.kubernetes.io/name: echo-pod
name: echo-pod
spec:
ports:
- name: http
nodePort: 30162
port: 80
protocol: TCP
targetPort: 8080
selector:
app: echo-pod
type: NodePort
NodePort is being used here but ClusterIP can also be used.
Now, the service should be created.
kubectl get service -l app=echo-pod
Next, create ingress file. Take note the certificate-arn annotation, where you have to use your certificate ARN from ACM. Host name must be updated to your host name, too.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-2:xxxxx:certificate/xxxxxxx
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
labels:
app: echo-pod
app.kubernetes.io/name: echo-pod
name: echo-pod-ingress
spec:
ingressClassName: my-alb-ing-class # or whatever ingress class name of ELB
rules:
- host: nayyaung.com # change it to your host name here
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: ssl-redirect
port:
name: use-annotation
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: echo-pod
port:
name: http
tls:
- hosts:
- nayyaung.com # change it to your host name here
Finally, you will see ALB being created. Wait for it to reach Active stage then go over to Route53 console to create host record using your host name and map it to the ALB just being created.
One interesting things to notice:
"listen-ports" annotation has both p0rt 80 and 443. And the actions.ssl-redirect annotation is set up to redirect http traffic to https using ssl-redirect action. ssl-redirect action must be the first rule so that ALB will evaluate it first, details in here.
So, if the user uses port 80, ALB will reroute it to port 443, with given SSL certificate on that port, and terminate it before routing it via the ingress rule to echo-pod which is using only port 80 (without SSL).
Again, the code is available on my GitHub repository.
Thanks for reading.