In this guide, we’ll walk through the steps to set up Cert-Manager on a Kubernetes cluster, configure a Cloudflare API token for DNS-01 challenge validation, and issue SSL/TLS certificates for your domain. This process ensures that your applications are secured with Let’s Encrypt certificates, leveraging Cloudflare for DNS-based verification
Create CRD
Before installing Cert-Manager, it’s essential to apply the required Custom Resource Definitions (CRDs). These CRDs define the custom resources that Cert-Manager uses to manage SSL/TLS certificates and integrate seamlessly with Kubernetes.
Run the following command to install the CRDs
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.crds.yaml
Install cert-manager with helm
to simplify we can install cert-manager helm chart with this command
$ helm repo add jetstack https://charts.jetstack.io$ helm repo update
$ helm install cert-manager jetstack/cert-manager --version v1.12.0 --namespace cert-manager-playground
Creating a Cloudflare API Token

Once created, save the API token securely, as it will be added to your Kubernetes cluster as a secret.
Adding the Cloudflare API Token to Kubernetes
Create a Kubernetes secret to store your Cloudflare API token. Replace <change_with_your_api_token>
with your actual token:
apiVersion: v1kind: Secretmetadata:name: cloudflare-api-tokennamespace: cert-manager-playgroundtype: OpaquestringData:api-token: <change_with_your_api_token>
Apply the secret
kubectl apply -f cloudflare-api-secret.yaml
Issuing a Certificate
To issue a certificate, create a Certificate resource. Below is a example for the domain opreks.my.id
apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: cloudflare-issuerspec:acme:email: <change_with_your_email>server: https://acme-v02.api.letsencrypt.org/directoryprivateKeySecretRef:name: cluster-issuer-account-keysolvers:- dns01:cloudflare:email: <change_with_your_email>apiTokenSecretRef:name: cloudflare-api-tokenkey: api-token
# certificate.ymlapiVersion: cert-manager.io/v1kind: Certificatemetadata:name: certificate-opreks-my-id #<change_with_your_cert_name>spec:duration: 2160h # 90drenewBefore: 360h # 15dsubject:organizations:- testorganizationprivateKey:algorithm: RSAencoding: PKCS1size: 2048dnsNames:- "*.opreks.my.id"secretName: certificate-opreks-my-idissuerRef:name: cloudflare-issuerkind: ClusterIssuergroup: cert-manager.io
$kubectl apply -f cluster-issuer.yaml$kubectl apply -f certificate.yaml
default 0s Normal cert-manager.io CertificateRequest/certificate-opreks-my-id-mtzx8 Certificate request has been approved by cert-manager.iodefault 0s Normal OrderCreated CertificateRequest/certificate-opreks-my-id-mtzx8 Created Order resource default/certificate-opreks-my-id-mtzx8-2839657829default 0s Normal Created Order/certificate-opreks-my-id-mtzx8-2839657829 Created Challenge resource "certificate-opreks-my-id-mtzx8-2839657829-4201251540" for domain "opreks.my.id"default 0s Normal Started Challenge/certificate-opreks-my-id-mtzx8-2839657829-4201251540 Challenge scheduled for processingdefault 0s Normal Presented Challenge/certificate-opreks-my-id-mtzx8-2839657829-4201251540 Presented challenge using DNS-01 challenge mechanismdefault 1s Normal DomainVerified Challenge/certificate-opreks-my-id-mtzx8-2839657829-4201251540 Domain "opreks.my.id" verified with "DNS-01" validationdefault 0s Normal Complete Order/certificate-opreks-my-id-mtzx8-2839657829 Order completed successfullydefault 0s Normal CertificateIssued CertificateRequest/certificate-opreks-my-id-mtzx8 Certificate fetched from issuer successfullydefault 0s Normal Issuing Certificate/certificate-opreks-my-id The certificate has been successfully issued
Logs and Validation
Once you’ve applied the configurations, the Cert-Manager will start the certificate issuance process. You can monitor the logs to ensure everything is working as expected. Here’s an example of successful logs:
echo 0s Normal Started Challenge/certificate-opreks-my-id-f45mg-3606330728-3498652677 Challenge scheduled for processingecho 0s Normal Presented Challenge/certificate-opreks-my-id-f45mg-3606330728-3498652677 Presented challenge using DNS-01 challenge mechanismecho 0s Normal DomainVerified Challenge/certificate-opreks-my-id-f45mg-3606330728-3498652677 Domain "echo.opreks.my.id" verified with "DNS-01" validationecho 0s Normal Complete Order/certificate-opreks-my-id-f45mg-3606330728 Order completed successfullyecho 0s Normal CertificateIssued CertificateRequest/certificate-opreks-my-id-f45mg Certificate fetched from issuer successfullyecho 0s Normal Issuing Certificate/certificate-opreks-my-id The certificate has been successfully issued
To validate our Kubernetes setup, we will deploy a simple echo service that responds to HTTP requests. This service will be useful for testing network connectivity and verifying the functionality of our cluster. Please create deployment.yaml file below
apiVersion: apps/v1kind: Deploymentmetadata:name: echo-servicenamespace: echolabels:app: echo-servicespec:replicas: 1selector:matchLabels:app: echo-servicetemplate:metadata:labels:app: echo-servicespec:containers:- name: echo-serviceimage: hashicorp/http-echo:latestargs:- "-text=Hello, World!"ports:- containerPort: 5678---apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: echo-ingress# annotations:# cert-manager.io/cluster-issuer: "cloudflare-issuer"namespace: echospec:ingressClassName: nginx-external # Specify the ingress class hererules:- host: echo.opreks.my.idhttp:paths:- backend:service:name: echo-serviceport:number: 80path: /pathType: ImplementationSpecifictls:- hosts:- echo.opreks.my.idsecretName: certificate-opreks-my-id---apiVersion: v1kind: Servicemetadata:name: echo-servicenamespace: echospec:selector:app: echo-serviceports:- protocol: TCPport: 80targetPort: 5678type: ClusterIP
$kubectl apply -f deployment.yaml
Testing access from the client using Nmap to verify the certificate
nmap --script ssl-cert -p 443 echo.opreks.my.idStarting Nmap 7.95 ( https://nmap.org ) at 2023-01-27 13:19 WIBNmap scan report for echo.opreks.my.id (54.169.147.155)Host is up (0.021s latency).Other addresses for echo.opreks.my.id (not scanned): 13.213.98.236rDNS record for 54.169.147.155: ec2-54-169-147-155.ap-southeast-1.compute.amazonaws.comPORT STATE SERVICE443/tcp open https| ssl-cert: Subject: commonName=echo.opreks.my.id| Subject Alternative Name: DNS:echo.opreks.my.id| Issuer: commonName=R11/organizationName=Let's Encrypt/countryName=US| Public Key type: rsa| Public Key bits: 2048| Signature Algorithm: sha256WithRSAEncryption| Not valid before: 2023-01-27T05:17:23| Not valid after: 2023-04-27T05:17:22| MD5: c623:85b3:6575:d70a:bf0b:0475:2d68:1cea|_SHA-1: db9a:17e1:0c12:5720:994b:57f2:b402:8b32:11dc:fe36