Struggling with certificates can be a headache, but luckily for us in Kubernetes we can use cert-manager and let it manage everything to easily create any certificate that we need.
In this how-to we will cover how to install cert-manager in our cluster as well as how to perform HTTP validation. We will also learn how to create a new certificate for our host by just appending an annotation to our ingress object.
Sounds good! What do I need?
I expect you to meet the following requirements:
- You have a working k8s cluster with nginx ingress-controller
- You have helm installed (read how to install helm)
- You have a domain you own targeting your cluster
- Desire to learn new things 🙂
Let’s start!
First of all we need to add the helm chart repository for cert-manager:
helm repo add jetstack https://charts.jetstack.io
Now, we proceed to create the namespace and deploy cert-manager in it:
kubectl create ns cert-manager helm upgrade --install cert-manager --namespace cert-manager --version v1.0.3 jetstack/cert-manager --set installCRDs=true
Just give it a few seconds to finish and you should receive a success message.
Creating a ClusterIssuer
We can use either an Issuer or a ClusterIssuer (namespace vs cluster-scoped). It’s the same exact thing, only changes the scope. The Issuer/ClusterIssuer represents the CA from which we want to get the new certificate, in this case we are using LetsEncrypt.
Note that the ClusterIssuer is actually a pretty simple object. The name and the secret name can be anything:
apiVersion: cert-manager.io/v1alpha3 kind: ClusterIssuer metadata: name: my-cluster-issuer spec: acme: email: {{ your email }} privateKeySecretRef: name: my-cluster-issuer server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingress: class: nginx
Issuing a new certificate
We are going to deploy a simple nginx, expose it as a service and then create an ingress for it. So, go ahead:
kubectl create deployment nginx --image nginx:alpine --namespace test kubectl expose deployment nginx --port 80 --target-port 80 --namespace test
Create a new ingress object to make it accessible through the ingress controller. Remember to replace with your actual domain in all ocurrences:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" labels: app: nginx name: nginx namespace: test spec: rules: - host: nginx.{{ your domain }} http: paths: - backend: serviceName: nginx servicePort: 80 path: / tls: - hosts: - nginx.{{ your domain }} secretName: nginx-certificate
Apply the new manifest:
kubectl apply -f ingress.yaml
If you try to access now to the host defined in the ingress, you’ll see an error message stating that “Your connection is not private”. To fix this, we are going to issue a new certificate. Edit the ingress that you just created and add the following annotation, replacing the value for whichever was the name you put in your ClusterIssuer:
cert-manager.io/cluster-issuer: my-cluster-issuer
Apply the ingress again (or save changes if your editing it) and now try to check the “cert” objects. You should get something like this:
kubectl get cert -n test NAME READY SECRET AGE nginx-certificate False nginx-certificate 21s
Now wait for about 1 or 2 minutes and when you check again…
kubectl get cert -n test NAME READY SECRET AGE nginx-certificate True nginx-certificate 93s
…we got our certificate! Go test it by refreshing the page or just opening a new tab and you should get the Nginx welcome screen. If you inspect the certificate you’ll see that it was indeed issued by LetsEncrypt:
Summarizing
What we saw here is:
- How to install cert-manager
- How to setup a new ClusterIssuer
- How to easily issue a new certificate
It was pretty easy overall, don’t you think so? In fact, when you know what to do you can easily replicate this setup virtually to any cluster in a matter of very few minutes.
Cert-manager will take care of all your certificate renewals. You can also create other Issuers or ClusterIssuers that support other CA or use other validation methods (DNS validation) but this is a more advance topic for the future.
I hope that you enjoyed this how-to and that it will be useful to you. Remember that if you need anything we will be glad to hear from you! Also check our blog for more useful posts like this one!