Certificate Issuer

Given that your cluster already has cert-manager and nginx-ingress already working, your next step would be to setup an Issuer or a ClusterIssuer

We will setup a staging ClusterIssuer:

letsencrypt-stg.yaml

This ClusterIssuer assumes you have installed nginx-ingress and cert-manager in the kube-system namespace, if that’s not the case, you should change the namespace metadata.

Let’s apply: kubectl apply -f letsencrypt-stg.yaml

We can check our created ClusterIssuer kubectl -n kube-system describe clusterissuer letsencrypt-stg

Explicit creation of a Certificate

For the majority of your services exposed via cert-manager you can use ingress-shim annotations, but the Kubernetes Dashboard it’s usually exposed only on HTTPS that interferes with the automatic Certificate generation.

Let’s use an explicit Certificate, then

Create the Certificate: kubectl apply -f kubernetes-dashboard-stg.yaml

Inspect your newly created resource: kubectl -n kube-system describe certificates kubernetes-dashboard-stg

At this point we should check the creation of our Certificate: kubectl -n kube-system describe certificate kubernetes-dashboard-stg

What you should see it’s something like:

Reason Message

------ -------

PrepareCertificate Preparing certificate with issuer

PresentChallenge Presenting http-01 challenge for domain your.awesome.host

SelfCheck Performing self-check for domain your.awesome.host

ObtainAuthorization Obtained authorization for domain your.awesome.host

IssueCertificate Issuing certificate...

CeritifcateIssued Certificated issued successfully

RenewalScheduled Certificate scheduled for renewal in 1438 hours

Certificate creation can also be tracked looking at your cert-manager pod, using this nested command:

kubectl -n kube-system logs -f $(kubectl -n kube-system get pods -l app=cert-manager -o jsonpath="{.items[0].metadata.name}") cert-manager

You should see something like this:

Setting lastTransitionTime for Certificate "kubernetes-dashboard-stg" condition "Ready"

Certificated issued successfully

Certificate scheduled for renewal in 1438 hours

certificates controller: Finished processing work item "kube-system/kubernetes-dashboard-stg"

certificates controller: syncing item 'kube-system/kubernetes-dashboard-stg'

Certificate scheduled for renewal in 1438 hours

certificates controller: Finished processing work item "kube-system/kubernetes-dashboard-stg"

Creation of the Ingress itself

Finally our system only lacks an Ingress to set everything in motion.

A working Ingress for the dashboard would be this one:

Some notable keys in this configuration:

secretName has to be the one specified in the Certificate above, as there is no automatic binding between those 2 resources.

kubernetes.io/ingress.class specifies which kind of LoadBalancer to use, if you’re using GKE or a Baremetal instance, nginx is the value you want.

nginx.ingress.kubernetes.io/ssl-redirect instructs NGINX to redirect HTTP traffic to HTTPS, there will be no HTTP version for your kubernetes dashboard, as the dashboard itself is served with HTTPS.

nginx.ingress.kubernetes.io/secure-backends specifies exactly that the Dashboard is serving in HTTPS only, so don’t expect an HTTP response, but an HTTPS one.

Commodity: full reference to nginx-ingress annotations

At this point navigating to https://your.awesome.host should show something like:

This is what looks like a staging Letsencrypt certificate on Chrome, does not seem like success. But it is.

If we reached correctly this step, we have mostly succeded, now we just have to duplicate all our resources for the Production deployment.

Production deployment

At this point a new ClusterIssuer, Certificate and Ingress will be necessary to move forward with the production Environment.

I will include an example of ClusterIssuer because it’s harder to come by online:

Just proceed to duplicate the other resources keeping in mind to use different names for the secrets, previously has been used the stg prefix for that very reason.

At the end of the proceeding we should get a working Dashboard URL:

Production letsencrypt certificate at work

So are we done yet? Not quite. We still have no privacy at all, the absolute minimal requirement would be a Basic Auth wall before reaching the Dashboard.

Basic Auth

First of all, let’s generate some credentials; we will use MD5 hash instead of Bcrypt (that’s more secure) because NGINX seems to have problems with it.

docker run --rm -it xmartlabs/htpasswd -m <user> <password >> htpasswd-dashboard

This command can be given multiple times to obtain a list of valid user/password combinations.

Once that is done, we will convert this file to a Kubernetes Secret

kubectl -n kube-system create secret generic htpasswd-dashboard --from-file=auth=htpasswd-dashboard

So, we have created a secret called htpasswd-dashboard containing an auth key that it’s our htpasswd file; NGINX wants the secret in this format.

We’ll have to add some metadata to our Ingress:

metadata: annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: htpasswd-dashboard nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"

Once we edited or applied our newly modified Ingress, we should be good to go.

When configuring Kubernetes, even getting a password prompt is a moment of success.

The objective was to expose the Kubernetes Dashboard securely, after the basic auth login you will have to provide a kubeconfig/ServiceAccount token.

With those tokens you can exploit the full granularity of Role based Access Control.

To the next time.

-Valerio