May 6, 2025

About

Until now, Let’s Encrypt has sent email notifications before TLS certificates expired. However, it seems that this notification service will be discontinued. As a result, there may be more cases where service providers fail to notice the expiration and their services become inaccessible.
This makes automated certificate management increasingly important.

However, in this unstable situation, my cert-manager failed to automatically renew the certificate. Since it took some time to resolve the issue, I’ve documented the troubleshooting process here for future reference.

Look for where the errors are…

When I checked certificate in k8s with this command,

kubectl get certificate -n ns

Below output was returned. As you can see, there is 404 eror when challenge was conducted.

  Type:      HTTP-01
  URL:       https://acme-v02.api.letsencrypt.org/acme/chall/----------
  Wildcard:  false
Status:
  Presented:   true
  Processing:  true
  Reason:      Waiting for HTTP-01 challenge propagation: wrong status code '404', expected '200'
  State:       pending
Events:
  Type    Reason     Age   From                     Message
  ----    ------     ----  ----                     -------
  Normal  Started    67s   cert-manager-challenges  Challenge scheduled for processing
  Normal  Presented  67s   cert-manager-challenges  Presented challenge using HTTP-01 challenge mechanism

I checked ingress next, but it is no doubt working.

kubectl get pods -A | grep ingress
ingress        nginx-ingress-microk8s-controller-ftbz5    1/1     Running   4 (31d ago)        91d

Lastly, I checked ingress class, It seems that I found something.

kubectl get ingressclass

NAME     CONTROLLER             PARAMETERS   AGE
nginx    k8s.io/ingress-nginx   <none>       2y85d
public   k8s.io/ingress-nginx   <none>       2y85d

Which ingressclass is one that is used as default?

If you execute the command, you can check the status of each ingressclass.

kubectl get ingressclass nginx -o yaml
kubectl get ingressclass public -o yaml

If you fine below settings from ingressclass, that ingressclass is used as default.

metadata:
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"

In my case, “public” is the default ingressclass.

Update Manifest of Cluster-Issuer

However, the ClusterIssuer manifest associated with my service didn’t include a setting for the default ingress class.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@your-domain
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: public  # ← nginx to public

So I changed the setting, as like showed above, nginx to public.

And then I connected the service with https correctly.

I hope cert-manage is going to update and manages certificates automatically.

Manifest of Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: public
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
    nginx.ingress.kubernetes.io/proxy-body-size: 50m
    nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0,::/0
  generation: 6
  name: yourservice-ingress
  namespace: yournamespace
spec:
  ingressClassName: public # setting this is important
  rules:
  - host: sub.yourdomain.com
    http:
      paths:
      - backend:
          service:
            name: yourservice_name
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - sub.yourdomain.com
    secretName: your-ingress-tls
status:
  loadBalancer:
    ingress:
    - ip: xxx.xxx.xxx.xxx

Check Certificate Request

microk8s kubectl describe certificaterequest -n yournamespace
  Conditions:
    Last Transition Time:  2025-05-02T14:28:45Z
    Message:               Certificate request has been approved by cert-manager.io
    Reason:                cert-manager.io
    Status:                True
    Type:                  Approved
    Last Transition Time:  2025-05-02T14:29:10Z
    Message:               Certificate fetched from issuer successfully
    Reason:                Issued
    Status:                True
    Type:                  Ready
Events:                    <none>