Capitulo 10: TLS con cert-manager

Por: Artiko
k3skubernetestlscert-managerletsencrypt

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:

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:

  1. Defines un ClusterIssuer que indica donde obtener certificados (Let’s Encrypt).
  2. Creas un Ingress con una anotacion que referencia al ClusterIssuer.
  3. cert-manager detecta el Ingress y solicita un certificado automaticamente.
  4. Let’s Encrypt valida que controlas el dominio (via HTTP challenge).
  5. cert-manager almacena el certificado en un Secret de Kubernetes.
  6. Traefik usa ese Secret para servir HTTPS.
  7. 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:

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:

  1. La anotacion cert-manager.io/cluster-issuer.
  2. La seccion tls con 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:

  1. Crea un recurso Certificate automaticamente.
  2. Crea un CertificateRequest hacia Let’s Encrypt.
  3. Let’s Encrypt crea un Order con un Challenge HTTP.
  4. cert-manager responde al challenge creando un pod temporal.
  5. Let’s Encrypt verifica y emite el certificado.
  6. 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:

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 —>