Let's Encrypt Kubernetes

Security is still an open question in the Cloud Native world. The inherently dynamic environment with short-lived containers, dynamic orchestrators, and network encapsulation provides significant challenges to traditional network security tools and procedures.

In general, cloud security best practices fall into three categories: Authentication, Authorization, and Encryption. While Authentication and Authorization are still a moving target in cloud-native deployments, there’s no reason we shouldn’t be encrypting all of our network traffic, both internal and external.

In this multi-part series, you will learn how to enable HTTPS (SSL/TLS) for applications deployed in Kubernetes. First we’ll walk through manually deploying and using TLS certificates in containerized applications. Then we’ll level-up our Kubernetes infrastructure by creating an automated certificate generator leveraging Let’s Encrypt, a free and open Certificate Authority. Finally, we will use our automatically created certificates to secure four services: NGINX, an Ingress Controller, a Node.js application, and a Golang application.

Hope you enjoy and don't hesitate to contact me if you or your company needs expert advice.

  • Part 1: Creating TLS certificates in Kubernetes
  • Part 2: Automatic TLS Certificates with Let's Encrypt (Coming soon!)
  • Part 3: Let's Encrypt Ingress (Coming soon!)
  • Part 4: Let's Encrypt NGINX (Coming soon!)
  • Part 5: Let's Encrypt Go (Coming soon!)
  • Part 6: Let's Encrypt Node.js (Coming soon!)

Part 1: Creating TLS certificates in Kubernetes

For the sake of simplicity and repeatability, we'll be using self-signed certificates for Part 1. I loosely followed this guide from the great folks at Digital Ocean on how to create a self-signed certificate.

The TLDR; is:


$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt

This will create two files in our current directory, tls.key and tls.crt. With these two files, we can enable TLS encryption for our applications. But first, we need to load these files into our Kubernetes cluster.

Creating a Kubernetes Secret with your Certificate

The next step is to deploy this certificate to our Kubernetes cluster.

We're going to be leveraging Kubernetes Secrets to store the TLS key and certificate.

Create the secret with:


$ kubectl create secret generic tls-certificate --from-file=./tls.key --from-file=./tls.crt
secret "tls-certificate" created

This command creates a new Secret called tls-certificate that has two data fields, one per file. We can see these data fields using kubectl describe:


$ kubectl describe secret tls-certificate
Name:        tls-certificate
Namespace:    tls
Labels:        
Annotations:    

Type: Opaque

Data

tls.crt: 1598 bytes tls.key: 1679 bytes

Note: the kubectl CLI does not print out the raw data in the Secret. If you really need to verify the information, you can use kubectl get secret tls-certificate -o yaml to get the base64 encoded TLS files.

OK! Our TLS certificate and key are now loaded into our Kubernetes cluster. Now it's time to use them!

Securing our application

For this demo, we're going to be using a simple Golang application that serves up a "Hello World" message, secured with TLS.

Here's our Golang app that reads tls.crt and tls.key from /secure/:


// main.go
package main

import ( "crypto/tls" "log" "net/http" )

func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, req http.Request) { w.Write([]byte("Hello world.\n")) }) cfg := &tls.Config{ MinVersion: tls.VersionTLS12, CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, PreferServerCipherSuites: true, CipherSuites: []uint16{ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_RSA_WITH_AES_256_CBC_SHA, }, } srv := &http.Server{ Addr: ":443", Handler: mux, TLSConfig: cfg, TLSNextProto: make(map[string]func(http.Server, *tls.Conn, http.Handler), 0), } log.Fatal(srv.ListenAndServeTLS("/secure/tls.crt", "/secure/tls.key")) }

I've already built a Dockerfile from scratch with this binary in it: rosskukulinski/secure-go-app. We can deploy this application using a Kubernetes Deployment file:

  

deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: secure-go-app spec:
template: metadata: labels: app: secure-go-app spec: containers: - image: rosskukulinski/secure-go-app imagePullPolicy: Always name: secure-go-app ports: - containerPort: 443 protocol: TCP volumeMounts: - mountPath: /secure/ name: tls-secret restartPolicy: Always volumes: - name: tls-secret secret: secretName: tls-certificate

Notice we're mounting our TLS Secret as a volume into our container in the /secure directory.

We can create this deployment:

 
$ kubectl create -f deployment.yaml deployment "secure-go-app" created

And assuming we've done everything correctly, one pod should be running:

 
$ kubectl get pods NAME READY STATUS RESTARTS AGE
secure-go-app-3505491896-7t47r 1/1 Running 0 5s

If a Pod isn't running (or not showing up!), I recommend checking out the 10 most common reasons Kubernetes Deployments fail.

Testing our secure application

Now let's verify the Pod is correctly responding to HTTPS requests by port-forwarding the container port 443 to our localhost port 1443.

 
$ kubectl port-forward secure-go-app-3505491896-7t47r 1443:443 Forwarding from 127.0.0.1:1443 -> 443
Forwarding from [::1]:1443 -> 443

Now we can make a request with curl:

 
$ curl -k https://localhost:1443 Hello world.

Woo! We've secured the network traffic to our example application with TLS encryption.

Next Steps

We have successfully secured an example application running in Kubenernetes with a self-signed certificate. If your organization has purchased TLS certificates from a Certificate Authority, you can follow this procedure to deploy them to Kubernetes.

While purchasing certificates from Giant-Certificate-Authority certainly makes sense for e-commerce or customer-facing websites, it can quickly get expensive for supporting services and inter-cluster communication.

One of the recent exciting developments in the web security space is Let's Encrypt, a free, automated, and open Certificate Authority. In Part 2 (coming soon!), you'll learn how to automatically generate TLS certificates in Kubernetes using Let's Encrypt.

Ross Kukulinski

My name is Ross. I teach the world Kubernetes and Nodejs through consulting, conference speaking, and training courses.

Philadelphia, PA