Strong, Simple SSL for Kubernetes Services
Hi, I’m Evan Brown
In the spirit of minimum viability, the first version of Jenkins-on-Kubernetes I built was very basic but functional: Here’s a visual of that first version: This works, but I have a few problems with it. First, authentication isn’t configured in a default Jenkins installation. The leader is sitting on the public Internet, accessible to anyone, until you connect and configure authentication. And since there’s no encryption, configuring authentication is kind of a symbolic gesture. We need SSL, and we need it now! For a few milliseconds I considered trying to get SSL working directly on Jenkins. I’d never done it before, and I caught myself wondering if it would be as straightforward as working with SSL on
I started by putting together a
Finally, start.sh evaluates the SERVICE_HOST_ENV_NAME and SERVICE_PORT_ENV_NAME env vars. These variables should be set to the names of the environment variables for the Kubernetes service you want to proxy to. In this example, the service for our Jenkins leader is cleverly named jenkins, which means pods in the cluster will see an environment variable named JENKINS_SERVICE_HOST and JENKINS_SERVICE_PORT_UI (the port that 8080 is mapped to on the Jenkins leader). SERVICE_HOST_ENV_NAME and SERVICE_PORT_ENV_NAME simply reference the correct service to use for a particular scenario, allowing the image to be used generically across deployments. LIke every other pod in this example, we’ll deploy Nginx with a replication controller, allowing us to scale out or in, and recover automatically from container failures. This excerpt from a
The pod will have a service exposing TCP 80 and 443 to a public load balancer. Here’s the service descriptor ): And here’s an overview with the SSL termination proxy in place. Notice that Jenkins is no longer directly exposed to the public Internet: Now, how did the Nginx pods get ahold of the super-secret SSL key/cert and htpasswd file (for basic access auth)? Kubernetes has an
You can create secrets in your cluster in 3 simple steps:In the beginning
Do what you know
SSL termination proxy as an nginx service
Defining the Controller and Service
spec:
containers:
-
name: "nginx-ssl-proxy"
image: "gcr.io/cloud-solutions-images/nginx-ssl-proxy:latest"
env:
-
name: "SERVICE\_HOST\_ENV\_NAME"
value: "JENKINS\_SERVICE\_HOST"
-
name: "SERVICE\_PORT\_ENV\_NAME"
value: "JENKINS\_SERVICE\_PORT\_UI"
-
name: "ENABLE\_SSL"
value: "true"
-
name: "ENABLE\_BASIC\_AUTH"
value: "true"
ports:
-
name: "nginx-ssl-proxy-http"
containerPort: 80
-
name: "nginx-ssl-proxy-https"
containerPort: 443
kind: "Service"
apiVersion: "v1"
metadata:
name: "nginx-ssl-proxy"
labels:
name: "nginx"
role: "ssl-proxy"
spec:
ports:
-
name: "https"
port: 443
targetPort: "nginx-ssl-proxy-https"
protocol: "TCP"
-
name: "http"
port: 80
targetPort: "nginx-ssl-proxy-http"
protocol: "TCP"
selector:
name: "nginx"
role: "ssl-proxy"
type: "LoadBalancer"
Keep it secret, keep it safe
$ cat ssl.key | base64
LS0tLS1CRUdJTiBDRVJUS...
apiVersion: "v1"
kind: "Secret"
metadata:
name: "ssl-proxy-secret"
namespace: "default"
data:
proxycert: "LS0tLS1CRUd..."
proxykey: "LS0tLS1CR..."
htpasswd: "ZXZhb..."
$ kubectl create -f secrets.json