Install cert-manager with Helm and DNS Resolver Settings

In this guide, we’ll walk through installing cert-manager using Helm on your Kubernetes cluster. We’ll also configure it to use specific DNS resolvers, which is helpful when working with split-horizon DNS or internal/external domains.


Prerequisites

  • A running Kubernetes cluster (v1.25+)
  • Helm installed (helm version)
  • Access to modify DNS records (e.g., Cloudflare)
  • DNS domain ready (e.g., maksonlee.com)
  • A Cloudflare API token stored in a Kubernetes Secret

  1. Add the cert-manager Helm Repository
helm repo add jetstack https://charts.jetstack.io --force-update

  1. Install cert-manager

We install cert-manager in its own namespace and configure it to create its required CRDs automatically:

helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.17.1 \
  --set crds.enabled=true \
  --set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=8.8.8.8:53\,1.1.1.1:53}'

The extraArgs section ensures cert-manager uses public recursive DNS servers to validate DNS-01 challenges, bypassing any internal DNS caching or split-horizon issues.


  1. Create Cloudflare API Token Secret

Create a Kubernetes Secret containing your Cloudflare API token (with permission to edit DNS records):

kubectl create secret generic cloudflare-api-secret \
  --from-literal=api-token=<YOUR_CLOUDFLARE_API_TOKEN> \
  --namespace cert-manager

  1. Create a ClusterIssuer (Staging)

We recommend testing with Let’s Encrypt staging first:

# clusterissuer-staging.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    email: cdlee123@gmail.com
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-staging-account-key
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: cloudflare-api-secret
              key: api-token

Apply it:

kubectl apply -f clusterissuer-staging.yaml

  1. Create a Certificate

Here’s an example of issuing a certificate for thingsboard.maksonlee.com:

# thingsboard-cert
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: thingsboard-cert
  namespace: thingsboard
spec:
  secretName: thingsboard-tls
  commonName: thingsboard.maksonlee.com
  dnsNames:
    - thingsboard.maksonlee.com
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer

Apply it:

kubectl apply -f thingsboard-cert

  1. Verification

Check certificate status:

kubectl describe certificate thingsboard-cert -n thingsboard

A successful output should include:

Type: Ready
Status: True
Reason: Ready
Message: Certificate is up to date and has not expired

  1. Switch to Production

Once staging works, change your ClusterIssuer to the production endpoint:

# clusterissuer-prod.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: cdlee123@gmail.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: cloudflare-api-secret
              key: api-token

Apply it:

kubectl apply -f clusterissuer-prod.yaml

Then update your Certificate to use the production issuer:

kubectl edit certificate thingsboard-cert -n thingsboard

Change:

issuerRef:
  name: letsencrypt-staging

to:

issuerRef:
  name: letsencrypt-prod

cert-manager will detect the change, invalidate the previous certificate, and issue a new one from production.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top