Todos los recursos

Guía práctica · cert-manager

cert-manager: Certificate está Ready, pero el Ingress sirve otro certificado

cert-manager indica Ready=True, pero el navegador sigue recibiendo un certificado antiguo o inesperado. Compara el certificado guardado en el Secret, el Secret al que apunta el Ingress y el certificado recibido en una nueva conexión TLS.

Esta guía trata Kubernetes Ingress con cert-manager cuando el controlador Ingress termina TLS. Adapta el contexto, el namespace, los nombres de los recursos y el nombre de host antes de ejecutar los comandos de diagnóstico de solo lectura. Requieren Bash en Linux, kubectl, OpenSSL y GNU coreutils. Gateway API y TLS passthrough siguen otras rutas de configuración.

1. Leer el estado del Certificate en el clúster correcto

Define estas variables en una sesión de Bash y usa esa misma sesión para los comandos de Kubernetes que siguen. El contexto explícito evita dirigir las comprobaciones a otro clúster configurado como predeterminado. Lee las condiciones, los eventos, las fechas de validez y la fecha de renovación en la descripción del Certificate.

TLS_CONTEXT=your-context
TLS_NAMESPACE=apps
TLS_CERTIFICATE=site
TLS_INGRESS=site
kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
  get certificate "$TLS_CERTIFICATE"
kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
  describe certificate "$TLS_CERTIFICATE"

Ready=True describe el estado que cert-manager conoce de este Certificate. No es una prueba TLS externa. Si Ready es False o no aparece, sigue la causa indicada en el Issuer o ClusterIssuer referenciado y en el CertificateRequest. Los Orders y Challenges son pertinentes cuando el emisor usa ACME. Evita comenzar el diagnóstico borrando el Secret o forzando emisiones repetidas.

2. Obtener el certificado guardado en el Secret

Lee spec.secretName del Certificate para localizar el Secret exacto. El siguiente comando muestra la huella, el emisor, las fechas y los SAN del certificado público final. Leer un Secret requiere los permisos correspondientes en Kubernetes. No copies una exportación completa del Secret en registros o solicitudes de soporte.

set -o pipefail
TLS_SECRET=$(kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
  get certificate "$TLS_CERTIFICATE" -o jsonpath='{.spec.secretName}')
if [ -n "$TLS_SECRET" ]; then
  kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
    get secret "$TLS_SECRET" -o jsonpath='{.data.tls\.crt}' |
    base64 --decode |
    openssl x509 -noout -sha256 -fingerprint \
      -issuer -dates -ext subjectAltName
fi

Guarda la huella SHA-256 como valor esperado. Un certificado que cubre example.com puede ser distinto del que pretendías desplegar. Las fechas y los nombres ayudan al diagnóstico, pero la huella identifica el certificado que estás comparando.

3. Revisar el Secret al que apunta el Ingress

Revisa spec.tls[].secretName, spec.tls[].hosts, los hosts de las reglas de enrutamiento e ingressClassName. El Secret TLS debe estar en el mismo namespace que el Ingress. Su certificado debe cubrir el nombre de host. Comprueba que el controlador previsto gestione esa clase de Ingress y pueda leer el Secret.

kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
  get ingress "$TLS_INGRESS" -o yaml
kubectl --context "$TLS_CONTEXT" -n "$TLS_NAMESPACE" \
  describe ingress "$TLS_INGRESS"

Compara la referencia con spec.secretName del Certificate. Si la diferencia no es intencionada, corrige el manifiesto, los valores de Helm o la fuente de GitOps que gestiona el Ingress. Con un Ingress anotado, ingress-shim crea los recursos Certificate a partir de esa configuración; revisa las anotaciones antes de añadir otro Certificate para el mismo Secret. Si las referencias son correctas, busca errores de carga o permisos en los eventos y registros del controlador Ingress.

4. Comparar con una nueva conexión TLS

Ejecuta esta prueba desde fuera de la red de alojamiento, sobre un servicio que administres o tengas permiso para inspeccionar. Vuelve a definir el nombre de host si usas otra shell. SNI comunica al servidor el nombre solicitado. Compara la huella mostrada con la del Secret.

set -o pipefail
TLS_HOST=example.com
timeout 10 openssl s_client -connect "$TLS_HOST:443" \
  -servername "$TLS_HOST" </dev/null |
  openssl x509 -noout -sha256 -fingerprint \
    -issuer -dates -ext subjectAltName

El comando muestra el certificado presentado. No valida la confianza en la cadena ni la correspondencia del nombre de host. Un CDN o balanceador que termina TLS antes del Ingress puede servir legítimamente otro certificado. Comprueba ese componente y después el origen por separado, si es accesible. Para probar una dirección concreta, cambia el destino de -connect por IP:443 o [IPv6]:443 y conserva -servername. Repite la comprobación para las direcciones y réplicas del controlador pertinentes.

5. Reproducir la diferencia en un clúster temporal

El script crea un clúster kind dedicado, instala cert-manager y utiliza Traefik como controlador Ingress. Un Issuer SelfSigned crea site-tls para renewal.test. El Certificate pasa a Ready, pero el Ingress apunta a stale-tls, que contiene otro certificado válido para el mismo nombre. Cambiar esa referencia a site-tls cambia el certificado recibido en la prueba TLS.

Descargar y revisar la demostración de cert-manager

Requisitos: un motor Docker local, kind, kubectl, curl, Bash, OpenSSL y GNU coreutils en Linux. Reserva varios GiB de memoria y espacio en disco para el clúster y las imágenes. Probado con kind 0.33.0, Kubernetes y kubectl 1.35.8, cert-manager 1.21.3 y Traefik 3.7.16.

Lee el script y ejecuta bash cert-manager-ingress-check.sh. Utiliza un kubeconfig privado y un reenvío de puerto por loopback; elimina su clúster y sus archivos temporales al salir. Las imágenes descargadas en el host permanecen en caché.

READY sigue siendo True, BEFORE difiere de EXPECTED y AFTER coincide con EXPECTED. Las aserciones comprueban estos valores. La prueba cubre una emisión real mediante cert-manager y la carga en el Ingress con certificados autofirmados, no la validación ACME, la renovación ni la confianza de los navegadores públicos.

6. Verificar el resultado y configurar avisos de caducidad

Tras corregir la configuración, repite la prueba externa y anota la dirección, el SNI, la hora de observación y la huella. Si se sirve el certificado esperado pero el navegador lo rechaza, revisa la cadena, los nombres cubiertos y la confianza en el emisor. Renovar otra vez no resuelve todos los errores TLS.

Nocert observa periódicamente los certificados servidos por los puntos de terminación TLS accesibles y evalúa las reglas de aviso de caducidad en un ciclo diario. Comprueba el punto de terminación y la hora de observación, y configura los destinatarios. Este seguimiento complementa la prueba inmediata tras un despliegue. Nocert no modifica tu Secret de Kubernetes ni tu Ingress, no renueva el certificado ni garantiza que todos los visitantes reciban el mismo certificado.

Fuentes técnicas