How to Configure Cert-Manager with ZeroSSL on Kubernetes

Overview

Cert-manager allows us to automate certificate management and issuance on our Kubernetes clusters. Follow along to configure Cert-Manager with ZeroSSL on your Kubernetes cluster!

Follow along to configure a ZeroSSL ClusterIssuer, this guide assumes you've already installed cert-manager on your cluster. I recommend installing it via Helm, follow this guide to do so: Helm | cert-manager.

Cert-Manager

To install cert-manager on your cluster, I recommend using Helm. Install Helm by running:

Install Helm

1curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
2sudo apt-get install apt-transport-https --yes
3echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
4sudo apt-get update
5sudo apt-get install helm

Install Cert-Manager

Now install cert-manager:

1helm repo add jetstack https://charts.jetstack.io
2
3helm repo update
1helm install \
2  cert-manager jetstack/cert-manager \
3  --namespace cert-manager \
4  --create-namespace \
5  --version v1.6.1 \
6  --set installCRDs=true

Verify cert-manager pods are running:

1kubectl get pod -n cert-manager

ZeroSSL

ZeroSSL offers unlimited 90 day SSL certificates, this is perfect for someone that needs many SSL certificates. There's also no rate limit for ZeroSSL compared to LetsEncrypt!

Create a ZeroSSL Account

Before we get started, you'll need a ZeroSSL account Sign Up - ZeroSSL.

After you've created your account, on your ZeroSSL dashboard, navigate to the Developer tab and generate your EAB credentials.

Create YAML Templates

Now that you have your credentials you'll want to create a secret on your kubernetes cluster.

Secret

1apiVersion: v1
2kind: Secret
3metadata:
4  namespace: cert-manager # Must be the namespace cert-manager is installed in
5  name: zerossl-eab
6stringData:
7  secret: <YOUR-HMAC-KEY-HERE>

ClusterIssuer

We'll also need to create a ClusterIssuer that will use these credentials to generate our certificates.

 1apiVersion: cert-manager.io/v1
 2kind: ClusterIssuer
 3metadata:
 4  name: zerossl-prod
 5spec:
 6  acme:
 7    # The ACME server URL
 8    server: https://acme.zerossl.com/v2/DV90
 9    externalAccountBinding:
10      keyID: <YOUR-EAB-KID>
11      keySecretRef:
12        name: zerossl-eab
13        key: secret
14    # Name of a secret used to store the ACME account private key
15    privateKeySecretRef:
16      name: zerossl-prod
17       # Enable the DNS-01 challenge provider
18    solvers:
19    - dns01:
20        # Replace the section below with your DNS01 provider
21        cloudflare:
22          email: <YOUR-CF-EMAIL>
23          apiTokenSecretRef:
24            name: cloudflare-api-token
25            key: api-token

DNS01 Provider

In my case, I'm using the DNS01 challenge for verification of my domain, and allowing the ClusterIssuer to add DNS entries to my domain that's managed via CloudFlare. You can learn how to add your DNS01 provider here DNS01 | cert-manager.

Apply YAML Template

Now let's put this all together into one file that we can apply to our cluster.

 1apiVersion: v1
 2kind: Secret
 3metadata:
 4  namespace: cert-manager # Must be the namespace cert-manager is installed in
 5  name: zerossl-eab
 6stringData:
 7  secret: <YOUR-HMAC-KEY-HERE>
 8---
 9apiVersion: cert-manager.io/v1
10kind: ClusterIssuer
11metadata:
12  name: zerossl-prod
13spec:
14  acme:
15    # The ACME server URL
16    server: https://acme.zerossl.com/v2/DV90
17    externalAccountBinding:
18      keyID: <YOUR-EAB-KID>
19      keySecretRef:
20        name: zerossl-eab
21        key: secret
22    # Name of a secret used to store the ACME account private key
23    privateKeySecretRef:
24      name: zerossl-prod
25       # Enable the HTTP-01 challenge provider
26    solvers:
27    - dns01:
28        # Replace the section below with your DNS01 provider
29        cloudflare:
30          email: <YOUR-CF-EMAIL>
31          apiTokenSecretRef:
32            name: cloudflare-api-token
33            key: api-token

Save this into a file e.g zerossl.yaml, then apply with kubectl apply -f zerossl.yaml.

Setup Ingress to Use the ClusterIssuer

Now all you'll need to do is add the following line to your Ingress configuration under annotations.

cert-manager.io/cluster-issuer: "zerossl-prod"

As an example

 1apiVersion: networking.k8s.io/v1
 2kind: Ingress
 3metadata:
 4  name: example
 5  namespace: example
 6  annotations:
 7    cert-manager.io/cluster-issuer: "zerossl-prod"
 8
 9spec:
10  ingressClassName: nginx
11  tls:
12  - hosts:
13    - www.example.com # replace with your fqdn
14    secretName: www-example-tls
15  rules:
16  - host: www.example.com # replace with your fqdn
17    http:
18      paths:
19      - path: /
20        pathType: Prefix
21        backend:
22          service:
23            name: nginx # replace with your service name
24            port:
25              number: 80

After applying your Ingress configuration the ClusterIssuer would request a certificate from ZeroSSL for www.example.com and place it in the secret www-example-tls. You'd then have secure encryption for your services! You can add multiple hosts and services to one Ingress as long as all of the services and Ingress are in the same namespace.

Conclusion

And that's all! You've now configured cert-manager to automatically issue certificates to your services with ZeroSSL. Feel free to contact me for help or if I should make any corrections to this blog post.

Troubleshooting

If anything goes wrong you can troubleshoot issues in a few ways.

Check ClusterIssuer

To see if the ClusterIssuer was successfully registered run

1kubectl describe clusterissuer zerossl-prod

if everything went smoothly you should see something like this

1 Conditions:
2    Last Transition Time:  2022-01-14T22:40:39Z
3    Message:               The ACME account was registered with the ACME server
4    Observed Generation:   1
5    Reason:                ACMEAccountRegistered
6    Status:                True
7    Type:                  Ready

Check CertificateRequest

To check the status of the certificate request first find the name of the request

1kubectl get certificaterequest -n <your-ingress-namespace>`

then

1kubectl describe certificaterequest <name-of-certificate-request> -n <your-ingress-namespace`

if everything went smoothly you should see something like this

 1Conditions:
 2    Last Transition Time:  2022-01-13T15:05:28Z
 3    Message:               Certificate request has been approved by cert-manager.io
 4    Reason:                cert-manager.io
 5    Status:                True
 6    Type:                  Approved
 7    Last Transition Time:  2022-01-13T15:08:05Z
 8    Message:               Certificate fetched from issuer successfully
 9    Reason:                Issued
10    Status:                True
11    Type:                  Ready