mTLS: confianza mutua entre servicios como fundamento de la seguridad este-oeste
El tráfico entre servicios dentro de un cluster se ha convertido en el nuevo perímetro. mTLS resuelve la pregunta de qué servicio está al otro lado de la conexión sin depender de tokens que se pueden robar y reutilizar. Entender su mecánica, su coste operativo y su encaje en la malla es condición previa para cualquier arquitectura Zero Trust seria.
Durante años la seguridad del tráfico interno fue un problema resuelto por la red: VLAN, firewalls perimetrales y la asunción de que lo que vivía dentro del cluster era confiable. Esa hipótesis se rompió el día en que un microservicio comprometido podía hablar con todos los demás sin ninguna prueba criptográfica de identidad. mTLS (mutual Transport Layer Security) es la respuesta técnica a ese colapso, y entenderla con profundidad es la base para discutir cualquier otra pieza de la seguridad este-oeste. Este artículo forma parte de la serie La evolución de la seguridad en aplicaciones modernas.
Por qué la autenticación de tokens no basta entre servicios
TLS (Transport Layer Security) en su forma habitual autentica solo al servidor. El cliente abre una conexión, valida el certificado que presenta el servidor contra una cadena de confianza y deriva claves de sesión. Esa es la dinámica de cualquier navegador contra un sitio web. En la versión 1.3 del protocolo, publicada como RFC 8446 en 2018, el handshake quedó reducido a una ida y vuelta, eliminó cifrados y modos inseguros, y normalizó el forward secrecy. TLS 1.3 es hoy el punto de partida razonable y cualquier arquitectura que siga aceptando TLS 1.2 con ciphers débiles está discutiendo otro problema distinto al de este artículo.
El punto es que TLS normal resuelve la confidencialidad y la autenticación del servidor, pero deja al cliente como un actor anónimo. En el mundo cliente-navegador eso es suficiente porque el usuario se autentica después con una cookie o un token. En el mundo servicio-servicio esa asimetría es inaceptable. El servicio de facturación necesita saber con certeza que quien le está llamando es el servicio de pedidos y no un pod malicioso que obtuvo un bearer token robado de un log.
La alternativa obvia, pasar un JWT (JSON Web Token) en cada petición, tiene un problema estructural: el token demuestra posesión, no identidad del canal. Un token filtrado en un core dump, en un log mal configurado o en una imagen de contenedor pública puede reutilizarse desde cualquier parte del mundo mientras siga vigente. mTLS elimina ese vector porque la autenticación no es un secreto portable, es la prueba criptográfica de que el otro extremo posee la clave privada asociada al certificado que presenta. Esa clave, si se gestiona con mínimo rigor, nunca sale del pod.
Mecánica del handshake mutuo
La extensión del TLS clásico
En el handshake mutuo, tras el ClientHello y ServerHello habituales, el servidor envía su cadena de certificados como siempre, pero añade un CertificateRequest indicando al cliente que debe presentar el suyo. El cliente responde con su propia cadena y firma un resumen del handshake con su clave privada en el mensaje CertificateVerify. Ambas partes validan la cadena contraria contra sus trust stores respectivos, comprueban validez temporal, revocación y restricciones, y solo entonces derivan las claves de sesión.
El detalle importante es que los trust stores de cliente y servidor no tienen por qué coincidir. En un cluster es habitual que ambos lados confíen en la misma CA interna, pero nada impide escenarios asimétricos, federaciones o el uso de trust bundles distintos por zona. Esa flexibilidad es precisamente la que SPIFFE (Secure Production Identity Framework For Everyone) aprovecha para definir dominios de confianza formalmente.
SNI, ALPN y suites de cifrado en la práctica
Tres detalles del protocolo merecen atención cuando uno opera mTLS a escala. SNI (Server Name Indication) permite que un mismo endpoint sirva varios certificados según el nombre que pide el cliente, algo habitual cuando un ingress termina mTLS para varios servicios. ALPN (Application-Layer Protocol Negotiation) negocia si la conexión va a transportar HTTP/1.1, HTTP/2 o gRPC, y su mala configuración rompe más meshes de lo que se reconoce. La selección de cipher suites en TLS 1.3 queda reducida a un conjunto auditado por el IETF, pero en entornos híbridos con TLS 1.2 la prohibición explícita de suites RSA estáticas y de cualquier cosa sin forward secrecy sigue siendo obligatoria.
El verdadero coste: el ciclo de vida del certificado
El handshake es la parte fácil. Lo que convierte mTLS en un problema operativo serio es el ciclo de vida de los certificados: emisión inicial, distribución a cada pod, rotación antes del vencimiento, revocación cuando un workload se compromete y distribución del trust bundle cuando cambia la CA. En un cluster con miles de pods efímeros, cada uno de esos verbos tiene que ser automático, rápido y observable. Hacerlo a mano con scripts es la ruta directa al incidente que todo el mundo teme: el certificado raíz caduca un sábado a las tres de la mañana y todo el tráfico interno se detiene.
mTLS en una malla de servicios
Automatización por sidecar
La razón por la que Istio, Linkerd y Consul Connect se adoptaron masivamente es que convirtieron mTLS en un problema resuelto. El patrón es el mismo: un sidecar (Envoy en Istio, linkerd2-proxy en Linkerd) intercepta todo el tráfico entrante y saliente del pod, presenta el certificado de workload en las conexiones salientes y valida el certificado del remoto en las entrantes. La aplicación sigue hablando HTTP en claro contra localhost y el sidecar hace todo el trabajo criptográfico.
La CA del control plane firma certificados de corta duración, normalmente por debajo de las 24 horas, y los rota automáticamente antes del vencimiento. El trust bundle se distribuye por el mismo canal. Esto desplaza la conversación desde “cómo gestiono cien mil certificados” a “cómo aseguro la CA del control plane”, que es un problema mucho más acotado.
Modos permisivo y estricto
En Istio el modo PERMISSIVE acepta tanto conexiones mTLS como en claro, y el modo STRICT rechaza cualquier conexión sin certificado válido. Esa dualidad existe porque la migración de un cluster existente a mTLS en un solo paso es inviable. La estrategia razonable es activar mTLS en permisivo globalmente, observar métricas y tráfico, identificar servicios que aún no presentan certificado, migrarlos uno a uno y endurecer a estricto por namespace cuando la evidencia dice que es seguro. Saltarse este baile y aplicar estricto de golpe rompe producción de forma espectacular.
mTLS sin malla
Montar mTLS sin service mesh es perfectamente posible y en algunos escenarios es la decisión correcta: clusters pequeños, requisitos de latencia extrema donde el sidecar es inaceptable, o arquitecturas con pocos servicios muy estables. El coste se paga en otra moneda: cada aplicación tiene que integrar una librería de TLS, gestionar su propia rotación, cargar los certificados con algún mecanismo (un operador de cert-manager con volumes, el Workload API de SPIFFE, un init container que llama a Vault) y tratar los fallos de handshake de forma homogénea. La decisión entre malla y no-malla se resume en si el equipo puede absorber esa complejidad distribuida en las aplicaciones o prefiere concentrarla en el data plane de la malla.
mTLS como primitiva para otras capas
Tokens vinculados al certificado
RFC 8705 (2020) define los Certificate-Bound Access Tokens: un access token OAuth 2.0 que solo es válido si la conexión TLS que lo transporta presenta el certificado de cliente cuyo thumbprint está embebido en el token. Esto elimina el replay: aunque el token se filtre, nadie que no posea la clave privada puede usarlo. Es la combinación natural de OAuth y mTLS en arquitecturas API donde el portador del token es un servicio, no un usuario.
SVID X.509 y la convergencia con SPIFFE
Un X.509-SVID, en la terminología de SPIFFE, es literalmente un certificado mTLS con un SAN URI con la forma spiffe://trust-domain/workload. La interoperabilidad con cualquier biblioteca TLS estándar es total. Esa decisión de diseño es lo que permite que SPIRE emita identidades consumibles por Envoy, por una aplicación Go con la librería estándar o por un servicio legacy sin modificación, siempre que el runtime pueda cargar el certificado.
Cuándo vale la pena y cuándo no
mTLS a gran escala tiene sentido en cuanto el cluster supera unas decenas de servicios, cuando hay requisitos regulatorios de cifrado en tránsito incluso dentro del perímetro, cuando la superficie multi-tenant exige garantizar aislamiento entre cargas, o cuando la arquitectura pretende alinearse con Zero Trust. No tiene sentido imponerlo en prototipos, entornos de desarrollo efímeros o sistemas donde la latencia del handshake domina el presupuesto de tiempo por petición y el session resumption no lo compensa.
Antes de imponer mTLS estricto, asegúrate de que el sistema de observabilidad distingue un fallo de handshake de un error aplicativo. Diagnosticar un 503 sin saber si viene de la aplicación o del sidecar agota a cualquier equipo de guardia.
Modos de fallo en producción
Los incidentes clásicos son cuatro. El primero es la expiración del certificado intermedio o raíz, a menudo oculta tras años de funcionamiento correcto. El segundo es la CA inalcanzable durante la rotación, que convierte una ventana de mantenimiento en caída general. El tercero es el clock skew entre nodos: un pod con la hora desviada cinco minutos rechaza como no-válido un certificado recién emitido. El cuarto es la cadena de validación mal configurada, típicamente cuando un trust bundle solo incluye la raíz y omite el intermedio activo.
Un certificado raíz caducado sin plan de rotación es el incidente de seguridad que más descubre la gente, siempre demasiado tarde.
Encaje arquitectónico
mTLS es la capa de transporte de la seguridad este-oeste, pero no sustituye a la autorización. Demostrar que el servicio A es quien dice ser no responde a si tiene permiso para invocar la operación X sobre el recurso Y. Esa decisión sigue correspondiendo a un motor de política, sea OPA evaluando reglas sobre el spiffe ID entrante o un authorization policy en la propia malla. El patrón limpio es mTLS como prueba de identidad, motor de política como prueba de permiso y observabilidad común que permita auditar ambos ejes. Cuando esa separación está bien hecha, la arquitectura tolera evolucionar los esquemas de política sin tocar la capa de transporte y al revés.
Artículos relacionados en esta serie
Referencias
- RFC 5280 (mayo 2008). Internet X.509 Public Key Infrastructure Certificate and CRL Profile.
- RFC 8446 (agosto 2018). The Transport Layer Security (TLS) Protocol Version 1.3.
- RFC 8705 (febrero 2020). OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens.
- SPIFFE. X.509-SVID Specification.
- Istio. Security Architecture Documentation.
- NIST SP 800-52 Rev. 2 (2019). Guidelines for the Selection, Configuration, and Use of TLS Implementations.