Building Platform Core FunctionalitiesStep 7 of 9: Step 5: Managing TLS Certificates with Cert-Manager
All Labs

Step 5: Managing TLS Certificates with Cert-Manager

In the meantime, we have a pretty solid foundation for our Kubernetes cluster. We have an Ingress Controller to manage inbound traffic, External Secrets to manage secrets, and External DNS to manage DNS records. The last piece of the puzzle is to manage TLS certificates for our services and ingresses. Fortunately, there is a Controller for that as well, called cert-manager.

Install Cert-Manager

To install cert-manager, we will use Helm again. The following commands will install cert-manager in your cluster:

helm repo add jetstack https://charts.jetstack.io --force-update
helm upgrade --install cert-manager --create-namespace --namespace cert-manager --set installCRDs=true --version v1.18.2 jetstack/cert-manager

This will install cert-manager in the cert-manager namespace and also install the necessary Custom Resource Definitions (CRDs) for cert-manager to work. To verify that everything is running as expected, you can check the pods in the cert-manager namespace:

kubectl get pods -n cert-manager

You should see three running pods for cert-manager: cert-manager, cert-manager-cainjector, and cert-manager-webhook, like this:

NAME                                      READY   STATUS    RESTARTS   AGE
cert-manager-595b985855-hhr6g             1/1     Running   0          23s
cert-manager-cainjector-dd577f84c-n8lzw   1/1     Running   0          23s
cert-manager-webhook-79cd9bf9d-mq5ms      1/1     Running   0          23s

Furthermore, you can check the logs of the cert-manager pod to see if it is working correctly:

kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager

If everything went fine, you should see no errors indicating that cert-manager is running and ready to manage TLS certificates.

As cert-manager is installed, we have to configure a so called Issuer or ClusterIssuer which defines how certificates should be issued. There are many different issuers available, for this lab we will use a self-signed issuer for testing purposes and a LetsEncrypt DNS issuer for DigitalOcean.

Issuers

Please note that cert-manager supports various issuers for TLS certificates, each with its own configuration requirements. Make sure to check the official documentation for the specific issuer you plan to use. In this lab, we provide a self-signed issuer as well as a LetsEncrypt DNS issuer for DigitalOcean as examples.

Option 1: Create a self-signed issuer

To create a self-signed issuer, we will create a new manifest file called self-signed-issuer.yaml with the following content:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-cluster-issuer
spec:
  selfSigned: {}

This manifest defines a new ClusterIssuer resource named selfsigned-cluster-issuer that uses self-signed certificates. To apply this manifest to your cluster, use the following command:

kubectl apply -f self-signed-issuer.yaml
Self-Signed Certificates and ClusterIssuers

Please note, that self-signed certificates are not trusted by browsers and should only be used for testing purposes. In a production environment, you should use a trusted issuer like Let's Encrypt. Furthermore, you might have noticed that we created a ClusterIssuer instead of an Issuer. The difference is that a ClusterIssuer is available cluster-wide, while an Issuer is only available in the namespace it is created in.

Option 2: Create a LetsEncrypt DNS ClusterIssuer for DigitalOcean

There are two ways to validate the ownership of a domain when using LetsEncrypt. The most common one is the HTTP validation, which requires that the domain is publicly accessible. If this is not the case, you can also use DNS validation, which requires access to the DNS provider. In this lab, we will use the DNS validation method, as it is more flexible and works in more scenarios. Furthermore, we will get a bit more practice with External Secrets.

In the first step, we will use the same manifests as before and create the Secret as well as the SecretStore for OpenBao in the cert-manager namespace. Please make sure to adjust the namespace in the commands accordingly.

kubectl create secret generic -n cert-manager vault-secret --from-literal=token=<your-openbao-token>
kubectl apply -n cert-manager -f secret-store.yaml
kubectl apply -n cert-manager -f externalsecret-dns.yaml

Please validate that everything is working as expected using the same commands as before. As we didn't change anything on our setup, the results should be the same as before.

To create a LetsEncrypt DNS ClusterIssuer for DigitalOcean, we will create a new manifest file called letsencrypt-dns-issuer.yaml with the following content:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: digitalocean-dns-issuer
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-staging-dns-issuer-account-key
    solvers:
    - dns01:
        digitalocean:
          tokenSecretRef:
            name: do-token
            key: do-token

This manifest defines a new ClusterIssuer resource named digitalocean-dns-issuer that uses Let's Encrypt as the certificate authority. It uses DNS-01 challenge type to validate the ownership of the domain, which requires access to the DNS provider. The API token for DigitalOcean is fetched from the Kubernetes secret we created before. To apply this manifest to your cluster, use the following command:

kubectl apply -f letsencrypt-dns-issuer.yaml

Verify the ClusterIssuer

To verify that the ClusterIssuer was created successfully, you can use the following command:

kubectl get clusterissuer

If everything went fine, you should see an output similar to this:

❯ kubectl get clusterissuer
NAME                        READY   AGE
digitalocean-dns-issuer     True    2m

This indicates that the ClusterIssuer is ready to be used. Now that we have an ClusterIssuer, we can create a Certificate resource to request a TLS certificate for our domain. There are many ways to do this, creating a Certificate resource is one of them. In our case we will go one step further, deploy a simple application with an Ingress resource and request a certificate for it.

🎉Cert-Manager is working

You have successfully set up TLS certificate management in your Kubernetes cluster using cert-manager and Let's Encrypt. In the next step, we will put everything together and deploy a sample application with an Ingress resource, which will automatically get a TLS certificate.