Capitulo 10: TLS con cert-manager
Capitulo 10: TLS con cert-manager
< Volver al Indice del Tutorial
Por que TLS es Obligatorio
Servir trafico HTTP sin cifrar en produccion no es una opcion. Las razones son claras:
- Los navegadores marcan sitios HTTP como “No seguros”.
- Los datos viajan en texto plano y pueden ser interceptados.
- Google penaliza sitios sin HTTPS en el ranking de busqueda.
- APIs sin TLS exponen tokens y credenciales en transito.
Traefik puede terminar TLS, pero necesita certificados. Obtenerlos y renovarlos manualmente es tedioso. cert-manager automatiza todo el proceso.
Que es cert-manager
cert-manager es un controlador de Kubernetes que gestiona certificados TLS de forma automatica. Se integra con proveedores como Let’s Encrypt usando el protocolo ACME (Automatic Certificate Management Environment).
El flujo funciona asi:
- Defines un ClusterIssuer que indica donde obtener certificados (Let’s Encrypt).
- Creas un Ingress con una anotacion que referencia al ClusterIssuer.
- cert-manager detecta el Ingress y solicita un certificado automaticamente.
- Let’s Encrypt valida que controlas el dominio (via HTTP challenge).
- cert-manager almacena el certificado en un Secret de Kubernetes.
- Traefik usa ese Secret para servir HTTPS.
- cert-manager renueva el certificado antes de que expire (cada ~60 dias).
Instalar cert-manager
La instalacion se hace con un solo manifest oficial:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yaml
Esto crea el namespace cert-manager y despliega tres componentes:
- cert-manager: el controlador principal.
- cert-manager-cainjector: inyecta certificados CA en webhooks.
- cert-manager-webhook: valida los recursos de cert-manager.
Verifica que los pods esten corriendo:
kubectl get pods -n cert-manager
Espera a que los tres pods muestren Running antes de continuar. Puede tomar un par de minutos.
kubectl wait --for=condition=Ready pods --all -n cert-manager --timeout=120s
ClusterIssuer para Let’s Encrypt
Un ClusterIssuer es un recurso que define como obtener certificados. A diferencia de un Issuer, funciona en todos los namespaces.
ClusterIssuer de Staging
Usa staging para pruebas. Los certificados no son validos para navegadores pero no tiene rate limits estrictos:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
class: traefik
ClusterIssuer de Produccion
Cuando confirmes que staging funciona, usa el issuer de produccion:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: traefik
Aplica ambos:
kubectl apply -f cluster-issuers.yaml
Verifica que esten listos:
kubectl get clusterissuer
La columna READY debe mostrar True para ambos.
Configurar Ingress con TLS Automatico
Para que cert-manager genere un certificado automaticamente, agrega dos cosas al Ingress:
- La anotacion
cert-manager.io/cluster-issuer. - La seccion
tlscon el host y el nombre del Secret.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mi-app-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.midominio.com
secretName: mi-app-tls
rules:
- host: app.midominio.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mi-app
port:
number: 80
Al aplicar este Ingress, cert-manager:
- Crea un recurso Certificate automaticamente.
- Crea un CertificateRequest hacia Let’s Encrypt.
- Let’s Encrypt crea un Order con un Challenge HTTP.
- cert-manager responde al challenge creando un pod temporal.
- Let’s Encrypt verifica y emite el certificado.
- cert-manager almacena el certificado en el Secret
mi-app-tls.
Certificate Resource
Puedes crear certificados manualmente sin depender de anotaciones en el Ingress:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: mi-app-cert
spec:
secretName: mi-app-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- app.midominio.com
- www.midominio.com
Esto es util cuando necesitas un certificado con multiples dominios (SAN) o cuando quieres gestionar el ciclo de vida del certificado independientemente del Ingress.
Troubleshooting
Cuando un certificado no se emite correctamente, sigue la cadena de recursos para diagnosticar:
Verificar el Certificate
kubectl get certificate
kubectl describe certificate mi-app-cert
Busca en la seccion Status y Events. El estado debe ser Ready: True.
Verificar el CertificateRequest
kubectl get certificaterequest
kubectl describe certificaterequest <nombre>
Verificar el Order
kubectl get order
kubectl describe order <nombre>
Verificar el Challenge
kubectl get challenge
kubectl describe challenge <nombre>
Los problemas mas comunes son:
- DNS no apunta al nodo: Let’s Encrypt no puede resolver el dominio a la IP de tu servidor.
- Puerto 80 bloqueado: el HTTP challenge necesita que el puerto 80 sea accesible desde Internet.
- Rate limit excedido: en produccion, Let’s Encrypt limita a 50 certificados por dominio por semana. Usa staging para pruebas.
- Nombre de ClusterIssuer incorrecto: verifica que la anotacion del Ingress coincida con el nombre del ClusterIssuer.
Un comando rapido para ver el estado general:
kubectl get certificate,certificaterequest,order,challenge
Ejemplo Completo
Vamos a exponer una aplicacion con HTTPS automatico. Asume que ya tienes cert-manager instalado y el ClusterIssuer de produccion creado.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-segura
spec:
replicas: 2
selector:
matchLabels:
app: web-segura
template:
metadata:
labels:
app: web-segura
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-segura
spec:
selector:
app: web-segura
ports:
- port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-segura-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- segura.midominio.com
secretName: web-segura-tls
rules:
- host: segura.midominio.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-segura
port:
number: 80
Aplica todo:
kubectl apply -f web-segura.yaml
Monitorea el progreso del certificado:
kubectl get certificate -w
Cuando la columna READY muestre True, tu aplicacion estara disponible en https://segura.midominio.com con un certificado valido de Let’s Encrypt que se renovara automaticamente.
Siguiente: Capitulo 11: Volumenes Persistentes —>