La corrección está integrada en el TP (Ver los recuadros verdes)
Lo que vas a aprender en este TP
- Lanzar la infraestructura multi-contenedor
- Configurar el equilibrio de carga HTTP
- Localizar y editar el fichero principal
- Utilizar la directiva include para la carpeta conf.d
- Comprender la diferencia entre reload y restart
- Configurar un frontend dedicado a las estadísticas
- Probar la accesibilidad del dashboard de estadísticas
- Configurar el frontend principal para el tráfico HTTP
- Configurar un backend por defecto
- Comprender el reparto de carga Round Robin
- Manipular las ACL path_beg
- Limitar las conexiones simultáneas (Anti-DoS/DDoS)
- Protegerse contra los ataques lentos (Slowloris)
- Poner en marcha un cupo de peticiones (Rate Limiting)
- Identificar y filtrar los autómatas (Anti-bot/Scraping)
- Utilizar la terminación silenciosa (Silent Drop) para los flujos prohibidos
Puesta en marcha de la infraestructura #
Lo que vas a aprender en esta secciónDespliegue de 3 servidores web, un servidor Nginx y un cluster HAProxy mediante Docker Compose.
- Lanzar la infraestructura multi-contenedor
- Configurar el equilibrio de carga HTTP
IMPORTANTE: Le recomendamos encarecidamente leer este artículo antes de comenzar este TP para dominar los fundamentos.
Obtención de fuentes
Debe clonar las fuentes del proyecto desde este REPO https://github.com/rousseltm/haproxy-formation.git en la carpeta que prefiera.
services: haproxy: image: haproxy:2.8 volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro ports: - "80:80" - "8404:8404" web1: image: httpd:alpine web2: image: httpd:alpinePuesta en marcha de la infraestructura
Para probar nuestras configuraciones necesitaremos una infraestructura mínima. Debe lanzar los siguientes comandos:cd haproxy-formation sudo docker compose -f compose-infra.yaml up -dSolo tiene que lanzar los comandos solicitados
Iniciación a la configuración #
Lo que vas a aprender en esta sección
- Localizar y editar el fichero principal
- Utilizar la directiva include para la carpeta conf.d
- Comprender la diferencia entre reload y restart
Exploración de la estructura de configuración y puesta en marcha de la modularidad.
Acceder al fichero base haproxy.cfg
El corazón de HAProxy reside en su fichero de configuración único. En nuestro entorno Docker, este fichero se monta en volumen.
El fichero se encuentra en
config/haproxy/haproxy.cfg. Puede abrirlo con su editor de texto habitual para observar las secciones Global y Defaults ya presentes.Añadir un include en el fichero
Para una gestión limpia, pediremos a HAProxy que cargue todos los ficheros de configuración terminados en .cfg situados en la carpetaconf.d.Añada la siguiente directiva en la sección
global:include /usr/local/etc/haproxy/conf.d/*.cfgTruco: Esto permite separar sus frontends y backends en ficheros distintos para mayor claridad.
Relanzar la configuración
Cada modificación del fichero requiere que sea tenida en cuenta por el motor HAProxy.
Reload vs Restart: En producción, no utilice nunca el restart ya que corta las conexiones. El Reload (señal HUP) permite cargar la nueva conf sin ninguna interrupción de servicio.
Para relanzar limpiamente con Docker Compose (Reload) :
Para un reinicio completo (Restart) :docker compose kill -s HUP haproxydocker compose restart haproxyPara saber más, consulte el artículo sobre las buenas prácticas de configuración.
Gestión de Frontends #
Lo que vas a aprender en esta sección
- Configurar un frontend dedicado a las estadísticas
- Probar la accesibilidad del dashboard de estadísticas
- Configurar el frontend principal para el tráfico HTTP
Configuración de los puntos de entrada para las estadísticas y el tráfico HTTP.
Punto de entrada para la administración
Cree un punto de entrada dedicado a la monitorización llamado 'admin'. Este punto de entrada debe escuchar en el puerto por defecto 8404. Debe activar la interfaz de estadísticas, definir la raíz (/) como URI de acceso y configurar un refresco automático cada 5 segundos. Note que puede realizar esta configuración con un bloquefrontendo un bloquelisten, el resultado será idéntico.El fichero de configuración se encuentra en la raíz de su carpeta de TP (
config/haproxy/haproxy.cfg). Para aplicar sus modificaciones, utilice el comandodocker compose restart haproxy.Puede editar el fichero de configuración haproxy para añadir esta configuración :
Y después relanzar el servicio.frontend admin bind :8404 stats enable stats uri / stats refresh 5sPrueba de acceso a las estadísticas
Después de haber configurado el frontend 'admin', verifique que la interfaz de monitorización está operativa. Puede utilizar su navegador o un comando de terminal para probar la accesibilidad del servicio en el puerto dedicado.
Verifique el acceso abriendo la siguiente URL en su navegador :
http://localhost:8404También puede validar la conetividad con
curl:curl -I http://localhost:8404Frontend HTTP
Configure el frontend principal llamado 'http_in' para recibir el tráfico web de los usuarios. Debe escuchar en el puerto 80 y redirigir por defecto todas las peticiones al grupo de servidores 'default' (que se creará posteriormente).
frontend http_in bind :80 default_backend default
Gestión de Backends #
Lo que vas a aprender en esta sección
- Configurar un backend por defecto
- Comprender el reparto de carga Round Robin
Configuración de los servidores de destino para tratar las peticiones.
El Backend por defecto
Cree un grupo de servidores llamado 'default'. Este backend se utilizará para tratar las peticiones que no coincidan con ninguna regla específica. Debe funcionar en modo HTTP, utilizar el algoritmo 'roundrobin' y apuntar al servidor 'web1'. Configure una regla para que este backend sirva sistemáticamente el fichero 'default.html'.
backend default mode http balance roundrobin # Reescritura del camino para mostrar la página de mantenimiento http-request set-path /default.html # Declaración de los nodos aplicativos server web1 web1:80 checkRecarga en caliente mediante fichero de conf
Abra su interfaz de estadísticas (puerto 8404). Normalmente debería ver 1 servidor activo en el backend default. El objetivo es añadir el servidor web2 a este pool 'en caliente', es decir, sin reiniciar el contenedor HAProxy, con el fin de preservar las conexiones en curso.1. Añada el servidor web2 en el bloque
backend defaultde su ficherohaproxy.cfg:server web2 web2:80 check2. Para recargar la configuración sin reiniciar el contenedor, envíe una señal de recarga (SIGHUP) al proceso HAProxy :
docker kill -s HUP <nombre_del_contenedor>Verifique en el dashboard de estadísticas : el backend default debe mostrar ahora 3 servidores sin que el Uptime del servicio se haya reiniciado.
Recarga en caliente mediante socat
HAProxy dispone de una Runtime API accesible mediante un socket Unix. Permite modificar el estado del balanceador de carga (peso, estado de los servidores, adición dinámica) sin ninguna recarga.Para inspeccionar el estado interno o pasar comandos directamente en su contenedor, conéctese a la shell mediante :
docker exec -it <nombre_del_contenedor> sh
Para utilizar la API, debe haber activado el socket en la sección global de suhaproxy.cfg:stats socket /var/run/haproxy.stat mode 600 level adminRecomendación de lectura : Para profundizar en la gestión dinámica de backends y servidores mediante la Runtime API, consulte nuestro artículo dedicado : HAProxy : Adición y supresión dinámica de backends.
1. Conéctese al contenedor HAProxy :
docker exec -it <nombre_del_contenedor> sh2. Utilice socat para enviar el comando de adición al motor :
echo "add server default/web3 web3:80 check" | socat stdio /var/run/haproxy.stat3. Por defecto, un servidor añadido dinámicamente está en modo mantenimiento. Actívelo :
echo "enable server default/web3" | socat stdio /var/run/haproxy.statVerifique en el dashboard : el servidor web3 aparece instantáneamente sin que el servicio se haya movido.
El Backend web_servers
Cree un grupo de servidores llamado 'web_servers'. Este backend debe funcionar en modo HTTP y utilizar el algoritmo de reparto 'roundrobin'. Debe también añadir una regla para transmitir la dirección IP real del cliente al backend mediante el encabezado 'X-Real-IP' y declarar los 3 nodos aplicativos (web1, web2, web3) en el puerto 80 con una verificación de salud (check).
backend web_servers mode http balance roundrobin http-request set-header X-Real-IP %[src] # Declaración de los 3 nodos aplicativos del cluster server web1 web1:80 check server web2 web2:80 check server web3 web3:80 checkEscalado de HAProxy
El paso a escala (scaling) horizontal consiste en multiplicar las instancias de HAProxy para garantizar la Alta Disponibilidad (HA). En una arquitectura real, tener una sola instancia de balanceador de carga crea un 'Single Point of Failure' (SPOF) : si HAProxy cae, toda la aplicación es inaccesible, incluso si los servidores web están sanos. En entorno Docker, el escalado permite repartir la carga de red y asegurar una continuidad de servicio durante las actualizaciones (rolling updates). Debe pasar el número de instancias HAProxy a 3.Para escalar su punto de entrada en el mundo Docker, utilizamos la capacidad de orquestación de Compose :
1. Configuración : Añada la directiva
scaleal servicio haproxy en su ficherocompose.yml:services: haproxy: image: haproxy:3.4-alpine scale: 3 # ... resto de la configuración2. Despliegue : Aplique la nueva topología :
docker compose up -d¿Por qué es esto importante?
- Resiliencia : Si un contenedor HAProxy falla, las otras instancias continúan respondiendo.
- Mantenimiento en caliente : Puede reiniciar o actualizar una instancia sin interrumpir el tráfico global.
- Rendimiento : En producción, estas instancias estarían repartidas en diferentes nodos físicos (mediante Docker Swarm o Kubernetes), permitiendo absorber caudales de red masivos.
Enrutamiento avanzado con ACL #
Lo que vas a aprender en esta sección
- Manipular las ACL path_beg
Redirigir las peticiones que comiencen por /api al servidor 2.
Modificación ACL
El enrutamiento inteligente permite dirigir el tráfico a diferentes backends según criterios precisos. En este ejercicio, debe configurar HAProxy para que identifique las peticiones destinadas a la API (que comiencen por el camino/api) y las envíe exclusivamente al servidor web2. El tráfico restante debe continuar siendo distribuido por el backend por defecto.IMPORTANTE : Asegúrese de comprender bien el esquema de arquitectura para garantizar que sus reglas de enrutamiento permitan siempre el acceso a la consola de estadísticas y al endpoint
/metrics.frontend http_in bind *:80 # Definimos una ACL que verifica si el camino comienza por /api acl is_api path_beg /api # Pedimos a HAProxy que utilice un backend específico si la ACL es verdadera use_backend api-backend if is_api default_backend web-servers backend api-backend server srv2 web2:80 checkListas blancas de IPs (Whitelisting)
El filtrado por dirección IP is un pilar de la seguridad. Debe ahora restringir el acceso al dashboard de estadísticas (puerto 8404) para autorizar solo la IP de su servidor Prometheus que necesita leer '/metrics' (por ejemplo 172.20.0.5).Whitelisting vs Blacklisting :
HAProxy es compatible con ambos enfoques mediante sus reglas de ACL.
- Whitelisting (Lista blanca) : Estrategia 'Default Deny'. Bloqueamos todo por defecto y solo autorizamos las fuentes conocidas. Es el enfoque más robusto para la seguridad.
Caso de uso : Acceso a una consola de administración, API interna reservada a partners, restricción de acceso a las IPs de una VPN de empresa. - Blacklisting (Lista negra) : Estrategia 'Default Allow'. Dejamos pasar todo el tráfico excepto las IPs identificadas como malintencionadas.
Caso de uso : Bloqueo de bots conocidos (scrapers), protección temporal contra una IP que realiza un ataque por fuerza bruta, o Geo-blocking (bloquear regiones enteras).
En entorno real, no olvide añadir las IPs de sus pasarelas VPN o de sus oficinas. Note que en nuestra infraestructura de TP, pasamos por un servidor Nginx de administración para acceder a HAProxy; es por tanto necesario autorizar su dirección de servicio Docker (
nginx-admin) además de la de Prometheus. Así se aplica este filtrado en el frontend de las estadísticas :frontend admin bind :8404 # Definición de la ACL basada en la IP de origen (src) acl network_allowed src nginx-admin 172.20.0.5 # Rechazamos el acceso si la IP no está autorizada http-request deny if !network_allowed stats enable stats uri / stats refresh 5sTruco de factorización : Si tiene una lista de IPs que desea reutilizar en varios frontends, evite copiarlas y pegarlas. Utilice un fichero externo (ej:
/etc/haproxy/whitelist.lst) que contenga una IP por línea. Su ACL se vuelve entonces simple y centralizada :acl network_allowed src -f /etc/haproxy/whitelist.lst- Whitelisting (Lista blanca) : Estrategia 'Default Deny'. Bloqueamos todo por defecto y solo autorizamos las fuentes conocidas. Es el enfoque más robusto para la seguridad.
Seguridad y Endurecimiento #
Lo que vas a aprender en esta sección
- Limitar las conexiones simultáneas (Anti-DoS/DDoS)
- Protegerse contra los ataques lentos (Slowloris)
- Poner en marcha un cupo de peticiones (Rate Limiting)
- Identificar y filtrar los autómatas (Anti-bot/Scraping)
- Utilizar la terminación silenciosa (Silent Drop) para los flujos prohibidos
Protección del cluster contra los abusos y los ataques de red.
Protección contra DOS y DDOS
Configure el frontendhttp_inpara limitar cada IP de origen a un máximo de 15 conexiones TCP simultáneas (Capa 4). Una vez aplicada la configuración, intente abrir varias conexiones en paralelo para verificar que HAProxy rechaza las siguientes.Verificación : Simule una carga con un bucle shell para abrir numerosas conexiones en segundo plano :
Mire sus logs de HAProxy o el dashboard : las conexiones por encima de 15 deben ser rechazadas inmediatamente.for i in $(seq 1 20); do curl -s http://localhost & done¿DoS vs DDoS : Cuál es la diferencia?
- DoS (Denial of Service) : El ataque proviene de una sola máquina. HAProxy puede bloquearlo fácilmente limitando las conexiones por IP.
- DDoS (Distributed DoS) : El ataque proviene de miles de fuentes (botnet). Bloquear una IP ya no es suficiente porque el tráfico está distribuido.
- Defensa en profundidad : Para los ataques volumétricos masivos (Capas 3 y 4), utilice servicios de protección Cloud (Cloudflare, AWS Shield) aguas arriba.
- Filtrado Capa 7 : Utilice HAProxy para identificar firmas de ataque específicas en los encabezados o las URLs mediante las ACL.
- Stick Tables : Siguen siendo esenciales para limitar el impacto de cada nodo de la botnet en sus recursos aplicativos.
Modo operativo :
- Modifique el fichero
haproxy.cfgpara integrar el seguimiento de las conexiones :
frontend http_in bind :80 # Creación de la tabla de seguimiento stick-table type ip size 100k expire 30s store conn_cur # Seguimiento de la IP de origen tcp-request connection track-sc0 src # Rechazo por encima de 15 conexiones tcp-request connection reject if { sc0_conn_cur gt 15 } default_backend web_servers2. Recargue HAProxy.
Protección contra Slowloris
El ataque Slowloris satura el servidor enviando encabezados HTTP muy lentamente. Implemente una protección limitando el tiempo de recepción de los encabezados a 5 segundos.Simulación de ataque : Lance este comando antes de la configuración (la conexión se quedará bloqueada) después después (HAProxy cortará la conexión tras 5s) :
Explicación de los parámetros :curl -X GET "http://localhost:80/" \ -H "X-Slow: $(head -c 5000 < /dev/zero | tr '\0' 'A')" \ --limit-rate 1 \ --verbose-H "X-Slow: ...": Genera un encabezado masivo de 5000 bytes (medianteheadytr) para forzar un envío largo.--limit-rate 1: Limita el envío a 1 byte/s. Sin protección, la conexión se quedaría abierta más de una hora.--verbose: Permite observar en directo el momento exacto en el que HAProxy interrumpe la sesión.
Recomendaciones de HAProxy (Leer el artículo oficial) : Para una protección óptima, HAProxy aconseja combinar varios ajustes :
timeout http-request 5s: Limita el tiempo de espera de los encabezados (defensa principal).timeout http-keep-alive 1s: Libera rápidamente los slots de conexión inactivos.maxconn: Limita el número global de conexiones para proteger los descriptores de ficheros del sistema contra el agotamiento.
Modo operativo :
- En la sección
defaults(o el frontend), añada la directiva de tiempo de espera (timeout) :
defaults # Corta la conexión si los encabezados tardan más de 5s en llegar timeout http-request 5s2. Recargue HAProxy y relance el comando de simulación. Debería ver un mensaje
Empty reply from servero un cierre de socket tras aproximadamente 5 segundos.Limitar las peticiones (Rate Limiting)
Ponga en marcha un cupo de 50 peticiones máximo cada 10 segundos por IP. Pruebe la superación del umbral y verifique que HAProxy devuelve correctamente un código de error HTTP 429.Verificación : Ejecute una ráfaga de peticiones curl para saturar el cupo :
Debe observar respuestasfor i in $(seq 1 60); do curl -I http://localhost; doneHTTP/1.1 429 Too Many Requestsdespués de la 50ª petición.Modo operativo :
- Actualice la stick-table del frontend
http_inpara seguir el caudal (http_req_rate) :
frontend http_in # Añadimos el almacenamiento del caudal en 10s stick-table type ip size 100k expire 30s store conn_cur,http_req_rate(10s) # Seguimiento a nivel HTTP (sc1) http-request track-sc1 src # Bloqueo con código 429 (Too Many Requests) http-request deny deny_status 429 if { sc1_http_req_rate gt 50 } default_backend web_servers2. Recargue la configuración.
- Actualice la stick-table del frontend
Módulos Anti-bot y Detección de scraping
Bloquee los aspiradores de datos (scrapers) y los bots malintencionados identificando sus firmas de User-Agent sospechosas.Simulación de bot : Intente acceder al sitio simulando un bot conocido mediante curl :
curl -I -H "User-Agent: Googlebot-Scraper" http://localhost/Modo operativo :
- Defina ACL basadas en los encabezados User-Agent en su frontend :
frontend http_in # Detección de palabras clave en el User-Agent (insensible a mayúsculas/minúsculas) acl is_bot hdr_sub(user-agent) -i bot crawler scraper spider # Rechazo de las peticiones identificadas como bots http-request deny deny_status 403 if is_bot default_backend web_servers2. Recargue HAProxy y verifique que su petición curl con el encabezado sospechoso es ahora rechazada por un código 403.
Terminación silenciosa de petición
El 'Silent Drop' es una técnica de defensa avanzada : en lugar de enviar un código de error (403/429) que confirme al pirata la existencia de una protección, HAProxy simplemente ignora la petición. El atacante malgasta sus recursos esperando una respuesta que nunca llegará.Verificación : Pruebe el acceso a un camino prohibido y compruebe que curl se queda esperando (hang) hasta el tiempo de espera :
curl -v http://localhost/admin/configModo operativo :
- Utilice la acción
silent-droppara los caminos o flujos prohibidos en el frontend :
frontend http_in acl is_forbidden path_beg /admin # Cierre de la conexión sin enviar el más mínimo bit de respuesta http-request silent-drop if is_forbidden default_backend web_servers2. Recargue la configuración. El cliente no recibirá ningún dato (ni siquiera un TCP RST), lo cual es particularmente eficaz contra los escáneres automáticos.
- Utilice la acción
Observabilidad #
Puesta en marcha de la monitorización, de la exposición de métricas y de la telemetría.
Stats Dashboard
Configure el listen admin.
listen admin bind *:8404 stats enable stats uri /stats stats refresh 5sPrometheus : Exposición de métricas
Configure HAProxy para exponer las métricas de rendimiento en formato Prometheus en la URI/metrics. Esto permite a un servidor Prometheus recolectar (scrape) el estado del balanceador de carga.Verificación : Pruebe la recuperación de las métricas mediante curl :
Debería ver desfilar las métricas en formato de texto plano (HELP and TYPE).curl http://localhost:8404/metricsModo operativo :
- En su bloque
listen admin, utilice la directivahttp-request use-service:
listen admin bind *:8404 stats enable stats uri /stats # Exposición de métricas para Prometheus # Esta regla intercepta las peticiones en la URI '/metrics' y devuelve el formato Prometheus http-request use-service prometheus-exporter if { path /metrics }2. Recargue la configuración. HAProxy sirve ahora las métricas en el mismo puerto que el dashboard.
- En su bloque
Soporte de OpenTelemetry (OTel)
Configure la exportación nativa de datos de telemetría hacia un colector OpenTelemetry.Nota : El soporte nativo de OpenTelemetry está disponible a partir de la versión 3.4 de HAProxy.
Modo operativo :
- Declare el exportador OTel en la sección
global:
global otel-exporter my-collector endpoint otel-collector:43172. Active el envío de trazas en su frontend para propagar el contexto :
frontend http_in http-request otel-send-trace- Declare el exportador OTel en la sección
Nivel de dificultad : ●●●○○ (3/5)