In this tutorial, we will be issuing Let’s Encrypt certificates using cert-manager on Kubernetes and we will be using the DNS Challenge with Cloudflare.
The reason I am using DNS Challenge instead of HTTP Challenge is because the Kubernetes environment is local on my laptop and there isn’t a direct HTTP route into my environment from the internet and I would like to not expose the endpoints to the public internet.
Summary of what we will be doing
We would like to have Let’s Encrypt Certificates on our web application that will be issued by Cert-Manager using the DNS Challenge from CloudFlare.
Our ingress controller will be ingress-nginx and our endpoints will be private, as they will resolve to private IP addresses, hence the reason why we are using DNS validation instead of HTTP.
Pre-Requisites
To follow along in this tutorial you will need the following
https://blog.ruanbekker.com/blog/2022/09/20/kind-for-local-kubernetes-clusters/
Cloudflare Account
Patience (just kidding, I will try my best to make it easy)
Install a Kubernetes Cluster
If you already have a Kubernetes Cluster, you can skip this step.
Define the kind-config.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Then create the cluster with kind
:
1
|
|
Nginx Ingress Controller
First we need to install a ingress controller and I am opting in to use ingress-nginx, so first we need to add the helm repository to our local repositories:
1
|
|
Then we need to update our repositories:
1
|
|
Then we can install the helm release:
1 2 3 4 5 6 |
|
You can view all the default values from their GitHub repository where the chart is hosted:
Once the release has been deployed, you should see the ingress-nginx pod running under the ingress-nginx
namespace:
1
|
|
Cert-Manager
The next step is to install cert-manager using helm, first add the repository:
1
|
|
Update the repositories:
1
|
|
Then install the cert-manager release:
1 2 3 4 5 |
|
Cloudflare API Token
We need to grant Cert-Manager access to make DNS changes on our Cloudflare account for DNS validation on our behalf, and in order to do that, we need to create a Cloudflare API Token.
As per the cert-manager documentation, from your profile select API Tokens, create an API Token and select Edit Zone DNS
template.
Then select the following:
Permissions:
Zone: DNS -> Edit
Zone: Zone -> Read
Zone Resources:
- Include -> All Zones
Then create the token and save the value somewhere safe, as we will be using it in the next step.
Cert-Manager ClusterIssuer
First, we need to create a Kubernetes secret with the API Token that we created in the previous step.
1 2 |
|
Then create the clusterissuer.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Then create the cluster issuer:
1
|
|
Request a Certificate
Now that we have our ClusterIssuer
created, we can request a certificate. In my scenario, I have a domain example.com
which is hosted on CloudFlare and I would like to create a wildcard certificate on the sub-domain *.workshop.example.com
Certificates are scoped on a namespace level, and ClusterIssuer’s are cluster-wide, therefore I am prefixing my certificate with the namespace (just my personal preference).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Before we create the certificate on CloudFlare, I have created private DNS to the names mentioned in the manifest above like the following:
1 2 |
|
In the DNS configuration mentioned above, to explain why I am creating 2 entries:
10.2.24.254
- This is my LoadBalancer IP AddressI have a static DNS entry to the name
workshop.example.com
so if my LoadBalancer IP Address ever change, I can just change this addressI am creating a wildcard DNS entry for
*.workshop.example.com
and I am creating a CNAME record for it to resolve toworkshop.example.com
so it will essentially respond to the LoadBalancer IP.So lets say I create
test1.workshop.example.com
andtest2.workshop.example.com
then it will resolve to the LoadBalancer IP inworkshop.example.com
and as mentioned before, if the LoadBalancer IP ever changes, I only have to update the A Record ofworkshop.example.com
Then after DNS was created, I went ahead and created the certificate:
1
|
|
You can view the progress by viewing the certificate status by running:
1
|
|
Specify the Certificate in your Ingress
Let’s deploy a nginx
web server deployment and I have concatenated the following in one manifest called deployment.yaml
:
Deployment
Service
Ingress
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
A few important things to notice on the ingress resource:
host
the host needs to match the certificatesecretName
the secret needs to match the secret defined in the certificate
Then create the deployment:
1
|
|
Ensure DNS Challenges are successful
Ensure that cert-manager can set DNS-01 challenge records correctly, if you encounter issues, you can inspect the cert-manager pod logs.
To view the pods for cert-manager:
1
|
|
Then view the logs using:
1
|
|
Test
You can open up a browser and access the ingress on your browser, in my case it would be https://nginx.workshop.example.com
and verify that you have a certificate issued from Lets Encrypt.
Thank You
Thanks for reading, if you enjoy my content please feel free to follow me on Twitter - @@ruanbekker or visit me on my website - ruan.dev