Configuración Avanzada de HAProxy: Terminación SSL

HAProxy es un potente balanceador de carga y proxy inverso de código abierto, renombrado por su rendimiento y flexibilidad. La terminación SSL/TLS en HAProxy descarga la sobrecarga de encriptación de los servidores backend, permitiendo manejo eficiente de tráfico HTTPS. Esta guía cubre configuraciones avanzadas de terminación SSL, gestión de certificados múltiples, listas de control de acceso (ACLs), persistencia de sesión y registro exhaustivo.

Tabla de Contenidos

  1. Conceptos Básicos de Terminación SSL/TLS
  2. Instalación y Configuración
  3. Configuración de Certificado Único
  4. Configuración de Múltiples Certificados
  5. ACLs y Enrutamiento
  6. Mapas para Enrutamiento Dinámico
  7. Stick Tables y Persistencia de Sesión
  8. Límites de Conexión
  9. Registro Avanzado
  10. Verificaciones de Salud
  11. Sintonización de Rendimiento
  12. Solución de Problemas

Conceptos Básicos de Terminación SSL/TLS

La terminación SSL/TLS en HAProxy proporciona varios beneficios:

  • Reduce la carga de CPU del servidor backend (sin sobrecarga de encriptación)
  • Centraliza la gestión de certificados
  • Habilita enrutamiento avanzado basado en propiedades SSL/TLS
  • Simplifica la configuración del servidor backend
  • Facilita la rotación y actualización de certificados

HAProxy descifra conexiones HTTPS entrantes y se comunica con backends sobre HTTP o HTTPS.

Instalación y Configuración

Instala HAProxy en Debian/Ubuntu:

sudo apt update
sudo apt install haproxy

Instala en RHEL/CentOS:

sudo yum install haproxy

Verifica instalación:

haproxy -v

Comprueba la configuración por defecto:

cat /etc/haproxy/haproxy.cfg

Inicia el servicio:

sudo systemctl enable haproxy
sudo systemctl start haproxy

Configuración de Certificado Único

Crea una configuración básica de HAProxy con terminación SSL:

sudo tee /etc/haproxy/haproxy.cfg > /dev/null <<'EOF'
global
    log stdout local0
    log stdout local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    
    tune.ssl.default-dh-param 2048
    tune.ssl.ciphers HIGH:!aNULL:!MD5
    tune.ssl.options ssl-default-bind-ciphers ssl-default-server-ciphers ssl-min-ver TLSv1.2

defaults
    log     global
    mode    http
    option  httplog
    option  denylogging
    timeout connect 5000
    timeout client  50000
    timeout server  50000

listen stats
    bind *:8404
    mode http
    stats enable
    stats uri /stats
    stats refresh 30s
    stats show-legends
    stats admin if TRUE

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    bind *:80
    
    mode http
    option httpclose
    option forwardfor except 127.0.0.1
    
    http-request redirect scheme https code 301 if !{ ssl_fc }
    
    default_backend web_servers

backend web_servers
    balance roundrobin
    mode http
    option httpchk GET /health HTTP/1.1\r\nHost:\ example.com
    
    server web1 192.168.1.100:80 check inter 2000 fall 3 rise 2
    server web2 192.168.1.101:80 check inter 2000 fall 3 rise 2
    server web3 192.168.1.102:80 check inter 2000 fall 3 rise 2 backup
EOF

Crea el archivo de certificado combinando el certificado y clave privada:

sudo mkdir -p /etc/haproxy/certs
sudo cat /path/to/certificate.crt /path/to/private.key > /etc/haproxy/certs/example.com.pem
sudo chmod 600 /etc/haproxy/certs/example.com.pem

Valida configuración:

sudo haproxy -f /etc/haproxy/haproxy.cfg -c

Recarga configuración:

sudo systemctl reload haproxy

Configuración de Múltiples Certificados

Maneja múltiples dominios con SNI (Server Name Indication):

sudo tee /etc/haproxy/haproxy.cfg > /dev/null <<'EOF'
global
    log stdout local0
    stats socket /run/haproxy/admin.sock mode 660 level admin

defaults
    log     global
    mode    http
    timeout connect 5000
    timeout client  50000
    timeout server  50000

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem crt /etc/haproxy/certs/api.example.com.pem crt /etc/haproxy/certs/blog.example.com.pem
    bind *:80
    
    mode http
    option httpclose
    option forwardfor
    
    http-request redirect scheme https code 301 if !{ ssl_fc }
    
    acl is_example_com hdr(host) -i example.com www.example.com
    acl is_api hdr(host) -i api.example.com
    acl is_blog hdr(host) -i blog.example.com
    
    use_backend backend_web if is_example_com
    use_backend backend_api if is_api
    use_backend backend_blog if is_blog
    default_backend backend_web

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check
    server web2 192.168.1.101:8000 check

backend backend_api
    balance roundrobin
    server api1 192.168.1.110:8080 check
    server api2 192.168.1.111:8080 check

backend backend_blog
    balance roundrobin
    server blog1 192.168.1.120:3000 check
EOF

Crea archivos de certificado:

sudo mkdir -p /etc/haproxy/certs

# Combina certificado y clave para cada dominio
sudo cat /etc/ssl/certs/example.com.crt /etc/ssl/private/example.com.key > /etc/haproxy/certs/example.com.pem
sudo cat /etc/ssl/certs/api.example.com.crt /etc/ssl/private/api.example.com.key > /etc/haproxy/certs/api.example.com.pem
sudo cat /etc/ssl/certs/blog.example.com.crt /etc/ssl/private/blog.example.com.key > /etc/haproxy/certs/blog.example.com.pem

sudo chown -R haproxy:haproxy /etc/haproxy/certs
sudo chmod 600 /etc/haproxy/certs/*.pem

ACLs y Enrutamiento

Usa ACLs (Listas de Control de Acceso) para decisiones de enrutamiento avanzadas:

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    bind *:80
    
    mode http
    option httpclose
    option forwardfor
    
    # Define ACLs
    acl is_api hdr(host) -i api.example.com
    acl is_admin path_beg /admin
    acl is_static path_beg /static /images /css /js
    acl is_mobile hdr(user-agent) -i smartphone mobile
    acl high_traffic src_conn_rate gt 100
    
    # Deniega fuentes de tráfico alto
    http-request deny if high_traffic
    
    # Enruta tráfico
    use_backend backend_api if is_api
    use_backend backend_static if is_static
    use_backend backend_admin if is_admin is_admin
    use_backend backend_mobile if is_mobile
    default_backend backend_web

backend backend_api
    balance roundrobin
    server api1 192.168.1.110:8080 check

backend backend_static
    balance roundrobin
    server cdn1 192.168.1.130:80 check

backend backend_admin
    balance roundrobin
    server admin1 192.168.1.140:8000 check

backend backend_mobile
    balance roundrobin
    server mobile1 192.168.1.150:3000 check

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check
    server web2 192.168.1.101:8000 check

Mapas para Enrutamiento Dinámico

Usa mapas para gestionar reglas de enrutamiento a través de archivos externos:

Crea un archivo de mapa de enrutamiento /etc/haproxy/maps/backends.map:

example.com                  backend_web
api.example.com              backend_api
blog.example.com             backend_blog
cdn.example.com              backend_static
admin.example.com            backend_admin

Referencia el mapa en la configuración de HAProxy:

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    bind *:80
    
    mode http
    option httpclose
    option forwardfor
    
    http-request redirect scheme https code 301 if !{ ssl_fc }
    
    use_backend %[req.hdr(host),lower,map(/etc/haproxy/maps/backends.map,backend_web)]

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check

backend backend_api
    balance roundrobin
    server api1 192.168.1.110:8080 check

backend backend_blog
    balance roundrobin
    server blog1 192.168.1.120:3000 check

backend backend_static
    balance roundrobin
    server cdn1 192.168.1.130:80 check

backend backend_admin
    balance roundrobin
    server admin1 192.168.1.140:8000 check

Actualiza mapas sin reiniciar HAProxy vía socket de administración:

echo "example.com backend_api" | socat - /run/haproxy/admin.sock

Stick Tables y Persistencia de Sesión

Implementa sesiones sticky usando stick tables:

global
    stats socket /run/haproxy/admin.sock mode 660 level admin

defaults
    mode http
    timeout connect 5000
    timeout client  50000
    timeout server  50000

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    bind *:80
    
    mode http
    option httpclose
    option forwardfor
    
    http-request redirect scheme https code 301 if !{ ssl_fc }
    
    stick-table type string len 32 size 100k expire 30m
    stick on cookie(JSESSIONID)
    
    default_backend backend_web

backend backend_web
    balance roundrobin
    
    stick-table type string len 32 size 100k expire 30m
    stick on cookie(JSESSIONID)
    
    server web1 192.168.1.100:8000 check
    server web2 192.168.1.101:8000 check
    server web3 192.168.1.102:8000 check

Usa stickiness basada en IP:

frontend https_in
    bind *:443 ssl
    
    stick-table type ip size 100k expire 30m
    stick on src
    
    default_backend backend_web

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check
    server web2 192.168.1.101:8000 check

Límites de Conexión

Implementa límites de conexión por cliente:

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    
    stick-table type ip size 100k expire 1m store http_req_rate(10s)
    
    http-request track-sc0 src
    http-request deny if { sc_http_req_rate(0) gt 100 }
    
    default_backend backend_web

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check maxconn 1000
    server web2 192.168.1.101:8000 check maxconn 1000

Limita conexiones concurrentes:

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem maxconn 10000
    
    default_backend backend_web

backend backend_web
    balance roundrobin
    server web1 192.168.1.100:8000 check maxconn 500
    server web2 192.168.1.101:8000 check maxconn 500

Registro Avanzado

Configura registro detallado de solicitudes:

global
    log 127.0.0.1 local0 debug
    log 127.0.0.1 local1 notice

defaults
    log     global
    mode    http
    option  httplog
    option  http-server-close
    option  denylogging
    
    log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"

El formato de registro se desglosa como:

  • %ci:%cp - IP:puerto del cliente
  • %tr - Marca de tiempo de solicitud
  • %ft - Nombre del frontend
  • %b/%s - Nombre de backend/servidor
  • %TR/%Tw/%Tc/%Tr/%Ta - Tiempos (solicitud, cola, conexión, respuesta, total)
  • %ST - Código de estado HTTP
  • %B - Tamaño de respuesta
  • %CC/%CS - Conteos de cookies
  • %tsc - Estado de terminación
  • %{+Q}r - Línea de solicitud

Ver logs:

tail -f /var/log/haproxy.log

Envía logs a syslog:

sudo tee /etc/rsyslog.d/49-haproxy.conf > /dev/null <<'EOF'
:programname, isequal, "haproxy" /var/log/haproxy.log
& stop
EOF

sudo systemctl restart rsyslog

Verificaciones de Salud

Configura verificaciones de salud avanzadas:

backend backend_web
    balance roundrobin
    option httpchk GET /health HTTP/1.1\r\nHost:\ example.com
    http-check expect status 200
    
    server web1 192.168.1.100:8000 check inter 2000 fall 3 rise 2 weight 1
    server web2 192.168.1.101:8000 check inter 2000 fall 3 rise 2 weight 2
    server web3 192.168.1.102:8000 check inter 2000 fall 3 rise 2 backup

backend backend_api
    balance roundrobin
    option tcp-check
    tcp-check connect port 8080
    
    server api1 192.168.1.110:8080 check inter 5000 fall 2 rise 1

Sintonización de Rendimiento

Optimiza HAProxy para escenarios de tráfico alto:

global
    tune.maxconn 200000
    tune.maxconnrate 4000
    tune.maxsslconn 100000
    tune.ssl.cachesize 1000000
    tune.ssl.lifetime 600
    tune.http.maxhdr 101
    tune.http.uri-max 8192
    tune.bufsize 32768

defaults
    mode http
    timeout connect 5s
    timeout client 50s
    timeout server 50s
    timeout tunnel 1h
    timeout http-keep-alive 1s
    option http-server-close
    option dup-cookie-names

Solución de Problemas

Comprueba estado de HAProxy:

sudo systemctl status haproxy
sudo tail -f /var/log/haproxy.log

Valida configuración:

sudo haproxy -f /etc/haproxy/haproxy.cfg -c

Monitorea estadísticas en tiempo real:

watch -n 1 'echo "show stat" | socat - /run/haproxy/admin.sock'

Prueba certificado SSL:

openssl s_client -connect localhost:443 -servername example.com

Comprueba expiración de certificado:

openssl x509 -in /etc/haproxy/certs/example.com.pem -noout -dates

Conclusión

HAProxy entrega terminación SSL/TLS de grado empresarial con características avanzadas para escenarios complejos de balanceo de carga. Sus poderosos ACLs, enrutamiento dinámico a través de mapas, persistencia de sesión con stick tables y capacidades exhaustivas de registro la hacen ideal para entornos de producción de alto tráfico. Combinado con verificaciones de salud sofisticadas y opciones de sintonización de rendimiento, HAProxy proporciona la base para infraestructura confiable y escalable.