SSL Options with Kubernetes – Part 3

Locked Container

In the first two posts in this series, SSL Options with Kubernetes – Part 1 and SSL Options with Kubernetes – Part 2, we saw how to use the Kubernetes LoadBalancer service type to terminate SSL for your application deployed on a Kubernetes cluster in AWS and Azure, respectively. In this post, we will see how this can be done for a Kubernetes cluster anywhere using an Ingress resource.

Rather than using an external load balancer as the AWS and Azure cloud providers do for the LoadBalancer service type, an ingress uses an Ingress Controller to provide load balancing, SSL termination and other services within a Kubernetes cluster. A big advantage of using an ingress is its portability across all clusters regardless of the underlying infrastructure, i.e. cloud, virtualized or bare metal. Until recently, a disadvantage was an ingress only supported HTTP and HTTPS and you would need to use a NodePort service type for other protocols. However, NGINX has added support for other protocols to their ingress controller.

Deploying an Ingress Controller

As always, in building our Kubernetes cluster, we will use Docker Enterprise. Docker is the leader in the enterprise container platform space, (https://www.docker.com/resources/report/the-forrester-wave-enterprise-container-platform-software-suites-2018), and makes it very easy to setup a highly available container cluster on (almost) any infrastructure with Kubernetes (and Swarm) orchestration.

Once you have your Kubernetes cluster up, the first choice you will have to make is what ingress controller to use. There are a wide range of ingress controllers available. Contour from Heptio (now VMware), NGINX from NGINX, Inc. (now F5) and Traefik from Containous are popular choices. And, you can use multiple ingress controllers if you find the need to take advantage of some unique capabilities each might provide. For this post, we are going to use the open source nginx ingress controller supported and maintained within the Kubernetes project itself.

To setup our nginx ingress controller, we’ll use Nicola Kabar’s excellent blog post, Production Ingress Deployment in Docker Enterprise UCP 3.1, as a starting point.

Another option for deploying the ingress controller is the nginx-ingress Helm chart.

Creating a Secret for our TLS Certificate

In our previous examples we’ve used a wildcard certificate for *.lab.capstonec.net issued by GoDaddy. We’ll use that same certificate in this example. First, we’ll create a Kubernetes secret, default-tls-certficate, in our ingress controller’s namespace, ingress in this example.

$ kubectl -n ingress create secret tls default-ssl-certificate --key key.pem --cert cert.pem
secret/default-ssl-certificate created

Update the Deployment to Specify the Secret

Once we have a secret with certificate we want to use, we need to update containers spec in the ingress controller’s deployment to include the --default-ssl-certificate command line option.

...
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1
          args:
            - /nginx-ingress-controller
            - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
            - --default-ssl-certificate=$(POD_NAMESPACE)/default-ssl-certificate
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --annotations-prefix=nginx.ingress.kubernetes.io
...

Specifying the Default SSL Certificate when using a Helm Chart

If you use the nginx-ingress Helm chart to deploy your NGINX ingress controller, you can specify the Kubernetes secret to use for the default SSL certificate when you install it.

You can pass it via the command line, i.e.

$ helm install --name nginx-ingress --set controller.extraArgs.default-ssl-certificate=default/default-ssl-certificate stable/nginx-ingress

Or you can pass it through an additional extraArgs.yaml file, i.e.

controller:
  extraArgs:
    default-ssl-certificate: "default/default-ssl-certificate"
$ helm install --name nginx-ingress --values=extraArgs.yaml stable/nginx-ingress

Deploying Our Application

As in our previous posts, we’ll use the nginx official image as our example web server. First, we create a deployment YAML file, kens-deployment.yaml.

kind: Deployment
apiVersion: apps/v1
metadata:
  name: kens-deployment
spec:
  selector:
    matchLabels:
      app: kens-app
  replicas: 2
  template:
    metadata:
      labels:
        app: kens-app
    spec:
      containers:
      - name: nginx
        image: nginx:1.15
        ports:
        - containerPort: 80

Then, we apply it using kubectl.

$ kubectl apply -f kens-deploment.yaml
deployment.apps/kens-deployment created

Next, we create a service manifest, kens-service.yaml.

kind: Service
apiVersion: v1
metadata:
  name: kens-service
spec:
  type: ClusterIP
  selector:
    app: kens-app
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80

And, apply it using kubectl.

$ kubectl apply -f kens-service.yaml
service/kens-service created

Creating an Ingress for Our Application

Finally, we need to create an Ingress manifest, kens-ingress.yaml. We want to access our service, kens-service, using the URL https://ken-nginx.lab.capstonec.net. In our manifest, we specify that TLS should be used for that host and we specify a rule that directs traffic for that host to our service.

kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  labels:
    app: kens-app
  name: kens-ingress
spec:
  tls:
  - hosts:
    - ken-nginx.lab.capstonec.net
  rules:
  - host: ken-nginx.lab.capstonec.net
    http:
      paths:
      - backend:
          serviceName: kens-service
          servicePort: 80
        path: /

We then apply this manifest using kubectl.

$ kubectl apply -f kens-ingress.yaml
ingress.extensions/kens-ingress created

Now, when we browse to our site, https://ken-nginx.lab.capstonec.net, we see a secure connection to our default web page.

welcome to NGINX

Overriding the Default SSL Certificate

If you don’t want to use the default SSL certificate for your application, you can create another secret, for example my-ssl-certificate, using your certifcate and key files. Then you would specify it in your ingress manifest as below.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  labels:
    app: kens-app
  name: kens-ingress
spec:
  tls:
  - hosts:
    - ken-nginx.lab.capstonec.net
    secretName: my-ssl-certificate
  rules:
  - host: ken-nginx.lab.capstonec.net
    http:
      paths:
      - backend:
          serviceName: kens-service
          servicePort: 80
        path: /

Want to know more?

In this series of posts we’ve looked at various options for terminating SSL for applications running in a Kubernetes cluster. The option you choose will depend upon your infrastructure and your application requirements. Capstone IT is a Docker Premier Consulting Partner as well as being an Azure Gold and AWS Select partner. If you are interested in finding out more and getting help with your Container, Cloud and DevOps transformation, please Contact Us.

Ken Rider
Solutions Architect
Capstone IT