Tu certificado de cert-manager se queda en pending y el reto HTTP-01 da 404
El Certificate sigue en READY False y el Challenge repite
"wrong status code '404', expected '200'". Me pasó en mi propio clúster k3s con la página ya abriendo con candado,
así que empiezo por lo que me engañó a mí.
1. Mira el estado real, no el candado del navegador
$ kubectl get certificate,order,challenge -A
$ kubectl describe challenge <nombre> -n <ns> | grep -A2 Reason
Reason: Waiting for HTTP-01 challenge propagation: wrong status code '404', expected '200'
Si el navegador muestra candado y aun así el Certificate está en False, el certificado que
ves lo emitió otra cosa. Ese es el caso más traicionero, porque todo parece bien hasta el día de la renovación.
2. Pide tú mismo la URL del reto
$ kubectl get ingress -n <ns> | grep acme-http-solver
$ kubectl get ingress <solver> -n <ns> -o jsonpath='{.spec.rules[0].http.paths[0].path}'
$ curl -sI http://tu-dominio/.well-known/acme-challenge/<token>
Lo que responda esa petición te dice cuál de las cuatro causas tienes.
3. Las cuatro causas y cómo distinguirlas
| Lo que ves | Causa | Corrección |
|---|---|---|
404 y en los registros de Traefik: Cannot retrieve the ACME challenge | Otro emisor ACME (el certResolver de Traefik) atiende /.well-known/acme-challenge de ese dominio | Deja un solo emisor: o todo con cert-manager, o el Ingress con traefik.ingress.kubernetes.io/router.tls.certresolver y sin secretName |
| 404 del backend por defecto | La ingressClassName del solucionador no es la de tu controlador | Fíjala en el emisor: solvers[].http01.ingress.ingressClassName |
| 403 o 301 | Un middleware (lista de IP por país, autenticación, redirección a HTTPS) se aplica también al reto. Let's Encrypt valida desde varias regiones, así que un filtro por país lo rompe | Excluye la ruta del reto del middleware o usa el reto DNS-01 |
| Tiempo agotado o conexión rechazada | El DNS no apunta al clúster o el puerto 80 está cerrado | dig +short tu-dominio y abre el 80 hacia el controlador |
4. Mi caso: dos emisores para un mismo dominio
$ kubectl -n kube-system logs deploy/traefik | grep "ACME challenge"
ERR Cannot retrieve the ACME challenge for labs.ingeniumcodex.com (token "ImPlJ6...")
Una ruta de Traefik del mismo dominio usaba certResolver: letsencrypt. Traefik se quedó con el reto,
emitió su propio certificado (el del candado) y cert-manager pasó nueve horas esperando un 200 que nunca iba a llegar.
Como el resto de mi clúster ya usa el resolvedor de Traefik, cambié la anotación del Ingress, quité el
secretName y borré el Certificate atascado:
metadata:
annotations:
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
spec:
tls:
- hosts: [tu-dominio]
Verificación: kubectl get challenge -A ya no lista nada y
openssl s_client -connect tu-dominio:443 -servername tu-dominio | openssl x509 -noout -issuer -enddate
muestra el emisor y la fecha de vencimiento.
Practica Kubernetes en tu propio clúster, gratis
Te envío al correo dos laboratorios completos con su solución: el 01 (namespace y deployment) y el 08 (ResourceQuota). Cada uno termina con un comando de verificación, no con "parece que funcionó".