tutoriales.com

Asegurando la Comunicación en Kubernetes: Implementando mTLS con Istio y Cert-Manager 🛡️

Este tutorial aborda la implementación de mTLS (Mutual TLS) en Kubernetes para asegurar la comunicación entre servicios. Utilizaremos Istio como Service Mesh y Cert-Manager para la gestión automatizada de certificados, proporcionando una capa robusta de seguridad para tus microservicios.

Intermedio25 min de lectura16 views
Reportar error

Introducción a la Seguridad en Kubernetes y mTLS 🛡️

En el mundo de los microservicios y Kubernetes, la comunicación segura entre componentes es más crucial que nunca. A medida que las aplicaciones se distribuyen en múltiples pods, nodos y clústeres, la superficie de ataque aumenta. Aquí es donde mTLS (Mutual Transport Layer Security) juega un papel fundamental. A diferencia del TLS unidireccional (donde solo el cliente verifica la identidad del servidor), mTLS requiere que ambos el cliente y el servidor se autentiquen mutuamente, asegurando que solo las identidades de confianza puedan comunicarse.

¿Por qué mTLS en Kubernetes? 🤔

  • Autenticación Fuerte: Verifica la identidad de cada servicio que intenta comunicarse, previniendo accesos no autorizados.
  • Cifrado de Tráfico: Todo el tráfico entre servicios está cifrado, protegiendo los datos en tránsito de escuchas indiscretas.
  • Confianza Cero (Zero Trust): Es un pilar fundamental del modelo de seguridad de confianza cero, donde ningún actor, interno o externo, se considera automáticamente digno de confianza.
  • Cumplimiento Normativo: Ayuda a cumplir con diversas regulaciones de seguridad que exigen cifrado y autenticación mutua.
🔥 Importante: Aunque Kubernetes ofrece funcionalidades básicas de red, no proporciona mTLS nativamente a nivel de aplicación. Para esto, necesitamos herramientas adicionales como un Service Mesh.

En este tutorial, exploraremos cómo implementar mTLS de forma robusta utilizando dos herramientas poderosas en el ecosistema de Kubernetes:

  1. Istio: Un Service Mesh de código abierto que proporciona funcionalidades de seguridad, observabilidad y control de tráfico.
  2. Cert-Manager: Una herramienta que automatiza la gestión y emisión de certificados TLS desde varias fuentes, como Let's Encrypt, HashiCorp Vault o CAs internas.

Componentes Clave: Istio y Cert-Manager ✨

Antes de sumergirnos en la implementación, es esencial entender el papel de cada herramienta.

Istio: El Service Mesh para la Seguridad 🕸️

Istio opera inyectando un sidecar proxy (Envoy) junto a cada pod de tu aplicación. Este proxy intercepta todo el tráfico de red entrante y saliente del pod, permitiendo a Istio aplicar políticas de seguridad, tráfico y observabilidad sin modificar el código de la aplicación.

Características clave de seguridad de Istio:

  • Autenticación: Istio proporciona una autenticación robusta basada en identidades de carga de trabajo, no en direcciones IP de red. Soporta mTLS con rotación automática de certificados.
  • Autorización: Permite definir políticas de acceso granular basadas en identidades de servicio, espacios de nombres, puertos, etc.
  • Cifrado: Cifra todo el tráfico entre los proxies de Envoy utilizando TLS.
Pod A App Container Envoy Proxy (Sidecar) Pod B App Container Envoy Proxy (Sidecar) Comunicación Lógica Comunicación mTLS

Cert-Manager: Automatización de Certificados 📜

Cert-Manager es un controlador de Kubernetes que añade certificados y emisores como tipos de recursos estándar en Kubernetes. Simplifica la emisión, renovación y uso de certificados TLS. Puede configurarse para obtener certificados de una variedad de fuentes, lo que lo hace increíblemente flexible.

¿Cómo encaja Cert-Manager con mTLS en Istio?

Tradicionalmente, Istio genera y gestiona sus propios certificados mTLS internos (CA de Istio). Sin embargo, en entornos empresariales o complejos, a menudo es deseable utilizar una PKI (Public Key Infrastructure) existente o una CA externa de confianza para emitir los certificados de identidad de los servicios. Aquí es donde Cert-Manager brilla, ya que podemos configurarlo para que sea la fuente de certificados para la CA de Istio, permitiendo una gestión centralizada y estandarizada de todos los certificados.


Requisitos Previos e Instalación 🛠️

Para seguir este tutorial, necesitarás lo siguiente:

  • Un clúster de Kubernetes en funcionamiento (v1.20+).
  • kubectl configurado para interactuar con tu clúster.
  • helm (v3.x) instalado para la instalación de Istio y Cert-Manager.

1. Instalar Cert-Manager 📦

Instalaremos Cert-Manager usando Helm. Se recomienda instalarlo en su propio namespace.

helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.12.0 \
  --set installCRDs=true

Verifica que los pods de Cert-Manager estén corriendo:

kubectl get pods --namespace cert-manager

Deberías ver algo similar a esto:

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-6585f9888-skcjc               1/1     Running   0          2m
cert-manager-cainjector-844c5ff4c7-8r4m6   1/1     Running   0          2m
cert-manager-webhook-77c858888b-w4j7d      1/1     Running   0          2m

2. Instalar Istio con Soporte para CA Externa 🌐

Ahora instalaremos Istio. Es crucial configurarlo para que use una CA externa (Cert-Manager) para sus certificados de identidad, en lugar de su CA interna predeterminada.

Primero, descarga istioctl:

cana curl -L https://istio.io/downloadIstio | sh -
cd istio-1.20.0 # Asegúrate de usar tu versión
export PATH=$PWD/bin:$PATH

Crearemos un archivo de configuración de Istio (istio-cert-manager.yaml) para definir nuestro perfil de instalación que delega la CA a Cert-Manager. Esto es clave para que Istio use certificados emitidos por nuestra CA externa.

# istio-cert-manager.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: default
  meshConfig:
    # Deshabilita la CA interna de Istio para que use la externa
    trustDomain: cluster.local
    # Habilita mTLS por defecto en todo el mesh
    defaultConfig:
      proxyMetadata:
        ISTIO_AGENT_USE_STS: "true"
  components:
    base:
      enabled: true
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
    egressGateways:
    - name: istio-egressgateway
      enabled: true
    pilot:
      enabled: true
      k8s:
        env:
        - name: CA_ADDR
          value: "istiod.istio-system.svc:15012"
        - name: EXTERNAL_CA
          value: "true"
        - name: EXTERNAL_CA_TYPE
          value: "CERT_MANAGER"
        - name: CERT_MANAGER_CA_NAME
          value: "istio-system-ca"
        - name: CERT_MANAGER_CA_NAMESPACE
          value: "istio-system"
📌 Nota: Este perfil configura `EXTERNAL_CA` a `true` y `EXTERNAL_CA_TYPE` a `CERT_MANAGER`, indicando a Istio que espere certificados de Cert-Manager. `CERT_MANAGER_CA_NAME` y `CERT_MANAGER_CA_NAMESPACE` especifican el nombre y el namespace del emisor que Cert-Manager usará para Istio.

Instala Istio usando este perfil:

istioctl install -f istio-cert-manager.yaml --set hub=docker.io/istio --set tag=1.20.0 -y

Verifica que Istio esté funcionando:

kubeactl get pods -n istio-system

Configurando la CA en Cert-Manager para Istio 🔑

Ahora que tenemos Cert-Manager e Istio instalados, necesitamos configurar Cert-Manager para que actúe como la CA para Istio. Esto implica crear un Issuer o ClusterIssuer y un Certificate para que Istio pueda obtener su certificado de CA de Cert-Manager.

Vamos a crear una CA raíz autofirmada gestionada por Cert-Manager que Istio utilizará. Esta CA emitirá los certificados de identidad para todos los servicios del mesh.

1. Crear un Emisor Raíz de Cert-Manager 🌳

Este ClusterIssuer actuará como nuestra CA raíz para el mesh de Istio. Podríamos usar una CA externa real, pero para este tutorial, una CA autofirmada es suficiente para demostrar el concepto.

# root-ca-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: istio-root-ca
spec:
  selfSigned: {}

Aplica este manifiesto:

kubectl apply -f root-ca-issuer.yaml

Verifica que el emisor esté listo:

kubectl get clusterissuers istio-root-ca

2. Crear un Certificado para la CA de Istio 📜

Ahora, crearemos un Certificate que utilizará el ClusterIssuer istio-root-ca para emitir un certificado para la CA intermedia de Istio. Este certificado se almacenará como un Secret en el namespace istio-system y será consumido por istiod.

# istiod-ca-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: istio-system-ca
  namespace: istio-system
spec:
  secretName: istio-system-ca-secret
  duration: 8760h # 1 año
  renewBefore: 4380h # 6 meses
  issuerRef:
    name: istio-root-ca
    kind: ClusterIssuer
  commonName: "istio-root-ca"
  isCA: true
  privateKey:
    algorithm: ECDSA
    size: 256
💡 Consejo: El `commonName` debe ser el mismo que `CERT_MANAGER_CA_NAME` que configuramos en el perfil de Istio.

Aplica este manifiesto:

kubectl apply -f istiod-ca-certificate.yaml

Verifica que el certificado se haya emitido correctamente y el secreto exista:

kubectl get certificate istio-system-ca -n istio-system
kubectl get secret istio-system-ca-secret -n istio-system

En este punto, istiod debería reiniciar automáticamente y empezar a usar este certificado como su CA de confianza para firmar los certificados de identidad de los servicios. Si no lo hace, puedes reiniciar los pods de istiod manualmente.


Desplegando una Aplicación de Prueba con mTLS ✅

Ahora que Istio está configurado para usar Cert-Manager como su CA, vamos a desplegar una aplicación de ejemplo para verificar que mTLS está funcionando correctamente.

Crearemos un namespace para nuestra aplicación y lo etiquetaremos para la inyección automática de sidecar de Istio.

kubectl create namespace example-app
kubectl label namespace example-app istio-injection=enabled

Usaremos una aplicación simple de httpbin y curl para demostrar la comunicación.

1. Desplegar httpbin y sleep 🚀

# example-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  namespace: example-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      serviceAccountName: httpbin
      containers:
      - image: docker.io/kennethreitz/httpbin
        name: httpbin
        ports:
        - containerPort: 80
--- 
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: example-app
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin
--- 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
  namespace: example-app
--- 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
  namespace: example-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      serviceAccountName: sleep
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep", "365d"]
        imagePullPolicy: IfNotPresent
--- 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sleep
  namespace: example-app

Aplica este manifiesto:

kubectl apply -f example-app.yaml

Espera a que los pods estén Running y que el sidecar istio-proxy esté inyectado (2/2 contenedores).

kubectl get pods -n example-app

2. Verificar mTLS entre servicios 🕵️‍♀️

Ahora, desde el pod sleep, intentaremos hacer una llamada HTTP al servicio httpbin.

kubectl exec deploy/sleep -n example-app -c sleep -- curl http://httpbin.example-app:8000/headers

Deberías ver una respuesta JSON con los encabezados HTTP. Esto indica que la comunicación se realizó correctamente. Pero, ¿cómo sabemos que mTLS se utilizó?

Podemos verificar el estado de mTLS utilizando istioctl.

istioctl authn tls-check sleep-xxxxxx-yyyy -n example-app

(Reemplaza sleep-xxxxxx-yyyy con el nombre real de tu pod sleep).

Deberías ver una salida similar a esta, indicando que el mTLS está STRICT:

SERVICE FQDN                                    CLIENT         SERVER         AUTHN POLICY      DESTINATION RULE   TLS MODE       
httpbin.example-app.svc.cluster.local           sleep-xxx-yyy  httpbin-aaa-bbb  default/STRICT    httpbin/STRICT     ISTIO_MUTUAL   
🔥 Importante: La columna `TLS MODE` mostrando `ISTIO_MUTUAL` y `AUTHN POLICY` como `STRICT` confirma que el tráfico entre `sleep` y `httpbin` está protegido con mTLS gestionado por Istio y, por extensión, por los certificados que Cert-Manager le ha proporcionado a la CA de Istio.

3. Forzar mTLS con Políticas de Autenticación 🔒

Por defecto, Istio configura el mTLS en modo PERMISSIVE, lo que significa que acepta tanto el tráfico mTLS como el tráfico plano. Para entornos de producción, es crucial forzar STRICT mTLS. Ya lo hemos visto en la verificación, pero podemos hacerlo explícitamente con un PeerAuthentication.

# peer-authentication.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: example-app
spec:
  mtls:
    mode: STRICT

Aplica este manifiesto:

kubectl apply -f peer-authentication.yaml

Esto aplica una política a todo el namespace example-app, forzando mTLS STRICT para todas las cargas de trabajo que se comunican dentro de él.

Ahora, si intentaras comunicarte con httpbin desde un pod sin el sidecar de Istio, la conexión fallaría.


Rotación de Certificados y Escalabilidad 🔄

Una de las grandes ventajas de usar Cert-Manager es la gestión automatizada de la rotación de certificados. El Certificate que definimos para istio-system-ca tiene una duración (duration) y un renewBefore especificados. Cert-Manager se encargará de renovar este certificado antes de que expire, sin intervención manual. Esto es crucial para mantener la seguridad a largo plazo y evitar interrupciones del servicio debido a certificados caducados.

La renovación del certificado de la CA de Istio a través de Cert-Manager activará automáticamente un proceso en Istio para que istiod obtenga el nuevo certificado de CA. A su vez, istiod firmará y distribuirá nuevos certificados de identidad para todos los sidecars de Envoy en el mesh. Este proceso es transparente para las aplicaciones.

Cert-Manager emite CA Root para Istio Istiod firma certificados de sidecars con CA Root Cert-Manager detecta renovación de CA Root Cert-Manager renueva CA Root Istiod detecta nuevo CA Root, solicita nuevo certificado de sidecars Sidecars obtienen certs y recargan configuración CICLO DE ROTACIÓN

Consideraciones para la Escalabilidad y Producción 📈

  • CA Externa Real: Para entornos de producción, considera usar una CA empresarial o un proveedor de CA externo (como HashiCorp Vault, AWS ACM Private CA) como emisor para Cert-Manager, en lugar de una CA autofirmada. Cert-Manager soporta una amplia gama de emisores.
  • Monitoreo: Monitoriza la salud de los pods de Cert-Manager e Istio, así como el estado de los certificados emitidos (kubectl get certificate -A).
  • Políticas de Malla: Utiliza PeerAuthentication a nivel de namespace o incluso de carga de trabajo para aplicar granularmente el modo mTLS (STRICT, PERMISSIVE).
  • Integración con Gateways: Para el tráfico de entrada al clúster (a través del Ingress Gateway de Istio), también puedes configurar mTLS para la comunicación entre clientes externos e internos, utilizando certificados emitidos por Cert-Manager.
⚠️ Advertencia: Una configuración incorrecta de mTLS o de la CA puede llevar a interrupciones del servicio. Siempre prueba tus configuraciones en entornos de no producción antes de aplicarlas en producción.

Limpieza de Recursos 🗑️

Para limpiar los recursos creados durante este tutorial:

  1. Eliminar la aplicación de ejemplo y el namespace:
kubectl delete -f example-app.yaml
kubectl delete namespace example-app
  1. Eliminar las políticas de Cert-Manager y el ClusterIssuer:
kubectl delete -f istiod-ca-certificate.yaml
kubectl delete -f root-ca-issuer.yaml
  1. Desinstalar Istio:
istioctl uninstall --purge -y
kubectl delete namespace istio-system
  1. Desinstalar Cert-Manager:
helm uninstall cert-manager --namespace cert-manager
kubectl delete namespace cert-manager
kubectl delete crds -l app.kubernetes.io/instance=cert-manager

Conclusión 🎉

La implementación de mTLS en Kubernetes es un paso crítico hacia una postura de seguridad robusta. Al combinar la potencia de Istio como Service Mesh y la automatización de certificados de Cert-Manager, hemos logrado una solución elegante y escalable para asegurar la comunicación entre tus microservicios.

Este enfoque no solo mejora la seguridad al garantizar la autenticación y el cifrado de todo el tráfico de servicio a servicio, sino que también simplifica la gestión de certificados, eliminando la carga manual y reduciendo el riesgo de errores. Integrar estas herramientas te acerca a un modelo de seguridad de Confianza Cero, esencial para las arquitecturas modernas de microservicios.

Has aprendido a:

  • Instalar y configurar Cert-Manager para emitir certificados.
  • Instalar Istio, delegando su CA a Cert-Manager.
  • Desplegar una aplicación de prueba y verificar que mTLS está activo.
  • Entender la importancia de la rotación automática de certificados.

Con estos conocimientos, estás bien equipado para proteger tus aplicaciones en Kubernetes con una capa de seguridad fundamental y automatizada.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!