Dos direcciones de tráfico, un solo nodo
Bienvenido
La mayoría de los diagramas de arquitectura muestran el tráfico en una sola dirección: el cliente arriba, el servidor abajo y una flecha apuntando hacia abajo. En la realidad, el tráfico fluye en ambas direcciones.
Tráfico de entrada (Ingress): los clientes externos acceden a tus servicios a través de esta ruta. Un proxy inverso en el borde de tu red termina la conexión TLS, enruta las solicitudes y aplica la política de acceso.
Tráfico de salida (Egress): tus servicios acceden a servicios externos a través de esta ruta. Llamando a la API de un procesador de pagos, obteniendo una URL de webhook o enviando una solicitud a un socio. Generalmente a través de un proxy directo o una pasarela NAT con una lista de permisos.
Muchas arquitecturas comienzan con una sola caja que maneja ambas funciones. Funciona, hasta el día en que deja de hacerlo. El modo de fallo es sutil, solo se manifiesta cuando existen suficientes servicios internos, y enseña una importante lección sobre la separación de responsabilidades.
Al finalizar esta lección, comprenderás:
- Por qué el tráfico de entrada (ingres) y de salida (egres) representan patrones fundamentalmente diferentes, con ejes de escalado distintos y modos de fallo diferentes
- NAT de horquilla (hairpin NAT) y por qué un proxy que intenta conectarse a sí mismo falla
- La bifurcación arquitectónica: una caja se convierte en dos, y qué es lo que cada una posee de forma exclusiva a partir de entonces
- Las ganancias en aislamiento de seguridad: cada lado puede restringirse a sus pares realmente permitidos
- Cómo identificar cuándo tu diseño de una sola caja ha cruzado el umbral en el que la división es necesaria
Por qué las direcciones exigen herramientas diferentes
Dos cargas de trabajo diferentes en un mismo límite de red
Características del tráfico de entrada (ingres):
- Iniciado por partes externas (el internet en general)
- El volumen escala con tu base de usuarios
- Terminación TLS, enrutamiento de solicitudes, limitación de tasa por origen
- Preocupaciones de defensa en profundidad: DDoS, abuso, raspado de datos
- La IP pública debe aceptar conexiones de cualquiera
Características del tráfico de salida (egres):
- Iniciado por tus propios servicios (un conjunto conocido y pequeño de clientes)
- El volumen escala con tus patrones de llamadas entre servicios y a APIs externas
- Lista de permisos de IPs de origen en los puntos de destino remotos (tienes una única IP de salida fija a la que los socios confían)
- Preocupaciones de defensa en profundidad: exfiltración de datos, servicios internos comprometidos que realizan llamadas salientes
- Debe rechazar las conexiones de cualquier persona que no sea tus propios servicios
La asimetría clave: la entrada (ingress) acepta tráfico del mundo; la salida (egress) acepta tráfico solo de tus propios servicios. Colocarlos en la misma máquina significa que esa máquina debe ser accesible simultáneamente desde el mundo (para la entrada) y solo desde tus servicios (para la salida). Las reglas del cortafuegos que satisfacen una trabajan en contra de la otra.
La ruta de crecimiento: un proyecto diminuto puede ocultar ambos detrás de una sola IP y una sola herramienta, porque el volumen es pequeño y la lista de IPs de socios permitidas es corta. A medida que el proyecto crece, la fricción entre los dos roles aumenta, y un día un modo de fallo específico (hairpin NAT) fuerza la separación.
El error que obliga a la separación
Una historia de interrupción sanitizada
Imagina un bifurcación arquitectónica real que ocurre en flotas de producción. Los nombres a continuación han sido cambiados; la forma es idéntica a lo que los equipos encuentran en la práctica.
Una organización opera un único servidor proxy en 203.0.113.5. Este maneja el tráfico de entrada (puerto 443 para usuarios) y de salida (puerto 1080 SOCKS5 para servicios internos que realizan llamadas salientes). Los servicios internos residen en subredes privadas y enrutan todo el tráfico saliente a través de ese proxy SOCKS5 en 203.0.113.5:1080.
Uno de los servicios alojados detrás del mismo 203.0.113.5 es api.example.com. El DNS público resuelve api.example.com a 203.0.113.5.
Ahora, un servicio interno diferente necesita llamar a api.example.com. Su ruta de salida es:
1. El servicio interno resuelve api.example.com → 203.0.113.5
2. El servicio interno envía la solicitud a través del proxy de salida SOCKS5 en 203.0.113.5:1080
3. El proxy intenta abrir una conexión desde sí mismo hacia 203.0.113.5:443
4. Conexión rechazada. El paquete tendría que salir y reingresar al mismo NAT, lo cual la mayoría de las pilas de red rechazan. El proxy no puede conectarse a sí mismo a través de su IP pública.
Esto es hairpin NAT: un paquete que sale de un NAT y necesita reingresar al mismo NAT para alcanzar su destino. Sin soporte especial de hairpin en la capa de enrutamiento, el paquete se descarta.
Por qué aparece tarde
Al inicio de la vida del proyecto, cada servicio interno se comunicaba con otros servicios internos mediante un nombre de host privado (internal-api.local) o no llamaba de vuelta a los servicios públicos de su propia organización. La ruta de hairpin simplemente no existía.
Luego, una nueva función requirió que el servicio A llamara a api.example.com (un nombre de host público). La ruta de hairpin se activó. Conexión rechazada. Caída del servicio.
La solución parchó el síntoma (forzar al resolutor para que diera la IP privada de api.example.com en lugar de la pública). La causa raíz: una sola máquina estaba haciendo demasiadas tareas.
La bifurcación arquitectónica
Una caja se convierte en dos
La solución limpia: separar el proxy en dos máquinas.
Servidor de entrada (IP pública 203.0.113.5):
- Caddy / proxy inverso en los puertos 80, 443
- Los registros DNS públicos apuntan aquí
- Aloja api.example.com, app.example.com, etc.
Servidor de salida (IP pública diferente 203.0.113.99):
- SOCKS5 / proxy de reenvío en el puerto 1080
- El cortafuegos restringe las conexiones entrantes solo a las IPs de la subred interna
- Los servicios internos enrutan todo el tráfico saliente a través de esta dirección
Lo que esto aporta:
1. Hairpin resuelto. Un servicio interno que llama a api.example.com enruta el tráfico saliente a través de 203.0.113.99 (egreso), que luego se conecta normalmente a 203.0.113.5 (ingreso, una IP diferente). El bucle NAT desaparece porque las dos IPs residen en máquinas diferentes.
2. Aislamiento de seguridad. El cortafuegos del servidor de egreso puede restringirse a un pequeño conjunto de IPs internas. El cortafuegos del servidor de ingreso permanece abierto al mundo. Dos conjuntos de reglas separados, cada uno expresando un rol de manera limpia.
3. Escala independiente. El ancho de banda de ingreso escala con los usuarios; el ancho de banda de egreso escala con la actividad de los servicios internos. Actualiza uno sin tocar el otro.
4. Aislamiento de fallos. Una configuración incorrecta del egreso ya no rompe el sitio público. Un DDoS contra el sitio público ya no agota el ancho de banda de egreso.
5. Modelo mental más claro. Cada máquina tiene una sola función. Los ingenieros razonan sobre las preocupaciones de ingreso sin pensar en el egreso, y viceversa.
Dos ejes, dos decisiones de dimensionamiento
Escalado independiente
Antes de la separación, el crecimiento en cualquier dirección sobrecargaba la misma máquina. Después de la separación, cada dirección tiene su propio aprovisionamiento.
Dimensionamiento de entrada (ingress): escala con los usuarios. Las decisiones de capacidad residen en la capa pública (más réplicas de proxy inverso, VMs más grandes, CDN en la parte frontal). El presupuesto de ancho de banda se calcula en función del tráfico de usuario en la hora pico.
Dimensionamiento de salida (egress): escala con el volumen de llamadas de servicios internos a APIs externas. A menudo está dominado por la entrega de webhooks, llamadas al procesador de pagos o la obtención de datos de terceros. El presupuesto de ancho de banda se calcula en función de los patrones de llamadas internas.
Aislamiento de fallos: un DDoS contra la entrada pública ya no consume el ancho de banda de salida (esas llamadas al procesador de pagos se realizan de todos modos). Un fallo en el proxy de salida ya no derriba el sitio público (los usuarios siguen llegando al sitio; solo fallan las llamadas salientes internas).
SLOs diferentes: la disponibilidad de la entrada es importante para los usuarios (interrupción visible del sitio); la disponibilidad de la salida es importante para los operadores (fallos en segundo plano que pueden tardar más en detectarse). Cada lado puede tener su propio SLO.
Múltiples servidores de salida
Una vez que el rol de salida es su propia máquina, el siguiente movimiento obvio es ejecutar varias máquinas de salida detrás de un equilibrador de carga para alta disponibilidad. Cada nuevo servicio interno apunta al nombre de host de salida (que se resuelve al pool equilibrado por carga) en lugar de a una única IP.
La misma lección que el resto de los sistemas distribuidos: una vez que un nivel se vuelve sin estado y tiene su propio rol, se multiplica de forma barata.
Una Nueva Integración de Socio
Tu organización ejecuta la separación de entrada/salida tal como está diseñada. El servidor de salida tiene una IP pública fija (203.0.113.99) que has autorizado en la lista blanca con tres APIs de socios existentes (un procesador de pagos, una pasarela de SMS y un proveedor de correo electrónico).
Un equipo de producto quiere agregar una cuarta integración: un sistema de entrega de webhooks que realiza llamadas de retorno a puntos de acceso de clientes en todo el mundo. Pronóstico de volumen: 10,000 llamadas por minuto, con picos de hasta 30,000.
Diseña un límite de red para un servicio en crecimiento
Síntesis
Has aprendido por qué la entrada (ingres) y la salida (egres) requieren herramientas diferentes, la falla de NAT hairpin que obliga a la separación en flotas reales, y cómo el escalado independiente, el aislamiento de seguridad y el aislamiento de fallos se acumulan una vez que se implementa la separación.
Aplica las cuatro.
Una empresa SaaS de tamaño medio opera tres subdominios de producto (app, api, admin) para sus usuarios, además de cuatro integraciones salientes (Stripe, Twilio, SendGrid, un sistema de webhooks de clientes). Hoy, todo reside detrás de una sola máquina proxy con una única IP pública. Han comenzado a recibir informes de fallos intermitentes de hairpin cuando los servicios internos intentan llamar a api.example.com. Quieren diseñar una solución permanente.
Hacia dónde va este curso
Hacia dónde va este curso
Has visto ahora uno de los refactorizaciones más limpias de separación de preocupaciones en sistemas distribuidos: una caja se convierte en dos, cada una con un rol claro, y el sistema hereda beneficios de escalabilidad, seguridad y aislamiento de fallos en el proceso.
La próxima lección (cs_distsys_failure_modes_and_blast_radius) amplía el razonamiento sobre el aislamiento de fallos. Leerás un análisis post-mortem sanitizado de un DNS-SERVFAIL, identificarás el patrón de fallo en cascada y redactarás acciones correctivas sin culpas que se centren en los sistemas en lugar de en las personas.
Lección complementaria: geometry_of_ingress_egress_separation reformula la separación como un grafo bipartito y explora los vértices de corte, las particiones de red y lo que la teoría de grafos te dice sobre un límite de red.
Buen trabajo. Adelante.