how to redirect http to https using a kubernetes ingress controller on Amazon EKS

You need to use the nginx.ingress.kubernetes.io/force-ssl-redirect: "true" annotation:

When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is no TLS certificate is available. This can be achieved by using the nginx.ingress.kubernetes.io/force-ssl-redirect: "true" annotation in the particular resource.


I was able to make it work!! basically I modified the ingress.yaml and service.yaml files

ingress.yaml looks like this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: metabase
  namespace: bigdata
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-2:***:certificate/****
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/group: metabase # name of my app

  labels:
    app: metabase

spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - path: /*
            backend:
              serviceName: metabase
              servicePort: 443

and my service looks like this:

apiVersion: v1
kind: Service
metadata:
  name: metabase
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-2:***:certificate/***
  namespace: bigdata
  labels:
    app: metabase
spec:
  ports:
    - name: https
      protocol: TCP
      port: 443
      targetPort: http-server
    - name: http
      protocol: TCP
      port: 80
      targetPort: http-server
  selector:
    app: metabase
  type: LoadBalancer

I have spent quite some time trying to make this work and finally succeeded. Probably someone will find it useful. I will try to describe step by step approach to setup ALB with HTTP to HTTPs redirect.

  1. Check that your ALB controller is up and running:
kubectl get deployment -n kube-system aws-load-balancer-controller

Printout should be similar to the one below:

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   1/1     1            1           18h

If your controller does not work, no Load Balancer will be created.

  1. Check that your yaml file is good. Below I provide a simple Yaml file that worked in my case. Some comments about this file:
    a) Please use your SSL/TLS certificate ARN (I used XXXXXXX).
    b) Please use your image (I used YYYYYYYYYY). My container image is stored in the ECR (Elastic Container Registry).
    c) Please note that a strange service marked ssl-redirect with servicePort:
    use-annotations is created according to the annotations specification.
    https://kubernetes-sigs.github.io/aws-load-balancer-controller/guide/ingress/annotations/

  2. Once you run: kubectl apply -f service.yaml Please check two things:
    a) kubectl -n default describe ingress
    This command should show that reconciliation was successful: the end of the printout should show:
    Normal SuccessfullyReconciled 11s (x3 over 18m) ingress Successfully reconciled
    In the same printout (top of the printout) do not pay attention to the log entry:
    /* ssl-redirect:use-annotation (<error: endpoints "ssl-redirect" not found>)
    b) aws elbv2 describe-load-balancers --query "LoadBalancers[?contains(LoadBalancerArn,'default-nginx')].{Arn: LoadBalancerArn}" --output text | xargs -I {} aws elbv2 describe-listeners --load-balancer-arn {}
    This command should show to you that a new ALB was created and two Listeners were created. Do not pay attention that the HTTP listener does not seem to have correct redirect configuration.


-- YAML --

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  namespace: default
  name: nginx-ingress
  annotations:
      kubernetes.io/ingress.class: alb
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/tags: createdBy=aws-controller
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
      alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
      alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-central-1:XXXXXXXXXXXX:certificate/XXXXXXXXXXXXXXXXXXXXXXXXXX

  labels:
    app: nginx-ingress

spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - path: /*
            backend:
              serviceName: nginx-service
              servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - name: http
      protocol: TCP
      port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: YYYYYYYYYYYY.dkr.ecr.eu-central-1.amazonaws.com/webfe:latest
        ports:
        - containerPort: 80