Problema

En muchos despliegues de Kubernetes se usan dos capas de balanceo: un VIP gestionado por Keepalived y un HAProxy que reenvía el tráfico a los pods de Traefik. Cuando el tráfico proviene de la red interna (VPN, túnel) llega sin problemas, pero cualquier petición desde la WAN termina en un reset o en una respuesta 404 de un servidor inesperado (por ejemplo, Microsoft‑HTTPAPI/2.0). El dashboard de HAProxy muestra cero sesiones para la IP pública, mientras que las capturas del firewall indican que el paquete se ha encaminado al VIP. El síntoma típico es:

  • HTTP a la IP pública → 404 de un servidor desconocido.
  • HTTPS a la IP pública → handshake abortado (connection reset).

El objetivo es identificar por qué el tráfico externo no alcanza el HAProxy y, en consecuencia, el Traefik.

Causa

Los fallos de este tipo suelen deberse a una de las siguientes áreas:

  1. ARP / MAC conflict – El firewall o el switch pueden estar aprendiendo la MAC equivocada para la VIP. Si otro dispositivo responde al ARP, el tráfico se dirige a un host que no ejecuta HAProxy (por ejemplo, un servidor Windows con HTTPAPI/2.0).

  2. Port‑forward / NAT mal configurado – En Fortinet, una regla de Virtual IP que apunta al VIP debe usar IP‑Pool o Static NAT sin traducción de origen. Si el origen se NATea al propio firewall, la respuesta vuelve por la ruta equivocada y el cliente ve un reset.

  3. Keepalived failover – Cuando el nodo maestro de HAProxy pierde la VIP pero el firewall sigue enviando tráfico a la MAC anterior, el paquete se descarta. El estado de MASTER/ BACKUP debe coincidir con lo que ve el switch.

  4. Política de firewall de salida – Algunas políticas bloquean paquetes con SYN a puertos 80/443 cuando el origen es la WAN y el destino es una IP interna (VIP). El firewall registra el forward, pero la regla deny posterior corta la sesión antes de que llegue al HAProxy.

  5. Envío de tráfico a la IP del host físico – En entornos KVM, el bridge de la NIC del hipervisor puede estar configurado en modo promiscuous desactivado. El paquete llega al hipervisor, pero no se entrega a la VM que posee la VIP.

  6. Problemas de MTU / fragmentación – Si la MTU del enlace WAN difiere de la del bridge interno, los paquetes pueden fragmentarse y ser descartados por HAProxy antes de abrir la sesión.

Solución

1. Verificar ARP y MAC en la red externa

# Desde una máquina en la WAN
arp -a | grep <VIP>
# En el firewall
diagnose ip arp list | grep <VIP>

La MAC debe coincidir con la del nodo HAProxy MASTER. Si aparecen dos entradas, elimina la estática que apunte al host incorrecto o desactiva la respuesta ARP del dispositivo que no debe responder.

2. Revisar la configuración de Virtual IP en Fortinet

En la GUI o CLI, asegúrate de que la VIP tenga:

  • External IP = WAN IP
  • Mapped IP = VIP (la IP flotante)
  • Port forwarding habilitado para 80 y 443, sin NAT de origen (opción Transparent o IP Pool vacío).

Ejemplo CLI:

config firewall vip
    edit "vip_haproxy"
        set extip <WAN_IP>
        set mappedip <VIP>
        set portforward enable
        set extport 80:443
        set mappedport 80:443
        set protocol tcp
    next
end

3. Confirmar el estado de Keepalived

# En ambos nodos HAProxy
sudo keepalived --dump-conf
ip addr show | grep <VIP>

Solo el nodo con state MASTER debe poseer la dirección. Si ambos la tienen, fuerza la prioridad o reinicia Keepalived.

4. Añadir regla de policy route para tráfico entrante

Algunos firewalls descartan paquetes cuyo origen y destino están en la misma zona. En Fortinet:

config firewall policy
    edit 0
        set srcintf "wan1"
        set dstintf "lan"
        set srcaddr "all"
        set dstaddr "vip_haproxy"
        set action accept
        set schedule "always"
        set service "HTTP" "HTTPS"
        set nat enable
    next
end

Asegúrate de que la política esté por encima de cualquier regla de denegación general.

5. Habilitar promiscuous mode en el bridge del hipervisor

En el host KVM:

virsh net-edit default
# Dentro del XML, agrega:
<forward mode='bridge'/>
<bridge name='br0' stp='on' delay='0'/>
<portgroup name='haproxy' trustGuestRxFilters='yes'/>

Reinicia la red del hipervisor y verifica que la VM con HAProxy reciba tráfico ARP para la VIP.

6. Probar sin MTU fragmentada

# En la VM cliente
ping -M do -s 1472 <VIP>

Si se pierden paquetes, ajusta la MTU del bridge a 1500 o usa mtu 1400 en la interfaz del host.

7. Validar el flujo con tcpdump

# En el nodo HAProxy MASTER
sudo tcpdump -i any host <WAN_IP> and port 80 or port 443 -vv

Deberías ver SYN → SYN‑ACK → ACK. Si sólo aparecen SYN y luego nada, el paquete está siendo descartado antes de llegar al proceso HAProxy.

Cuándo aplicar esta solución

  • Síntomas: HTTP/HTTPS funciona desde VPN pero no desde WAN; HAProxy dashboard muestra 0 sesiones para la IP pública; captura del firewall muestra forward correcto pero el cliente recibe reset o 404 de un servidor desconocido.
  • Entorno: Kubernetes con HAProxy + Keepalived + Traefik, firewall Fortinet o similar, hipervisor KVM.
  • No aplica: Cuando el problema es exclusivamente de certificados TLS (errores UNTRUSTED_ROOT) y el tráfico llega al pod, o cuando la aplicación dentro del pod responde con 5xx. En esos casos la causa está en la capa de aplicación, no en la red.

Código

# 1. Forzar prioridad en Keepalived (ejemplo)
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass secret
    }
    virtual_ipaddress {
        10.0.0.100/24 dev eth0 label eth0:vip
    }
}
# 2. Regla de iptables en el nodo HAProxy para asegurar que el tráfico llega
sudo iptables -I INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
sudo iptables -I FORWARD -p tcp -d 10.0.0.100 --dports 80,443 -j ACCEPT

Verificación

  1. Ping al VIP desde WAN – debe responder con la MAC del nodo MASTER.
  2. curl -v http://<WAN_IP> – respuesta 404 de HAProxy (código 404 de Traefik) indica que el request llegó al HAProxy.
  3. curl -vk https://<WAN_IP> – handshake completado y certificado presentado (aunque sea auto‑firmado).
  4. tcpdump – confirma la presencia de los paquetes SYN/ACK en la interfaz del nodo MASTER.
  5. Dashboard HAProxy – número de sesiones incrementa al hacer las pruebas desde WAN.

Si alguno de los pasos falla, revisa la sección correspondiente (ARP, VIP, keepalived, firewall policy).

Notas adicionales

  • En entornos con varios firewalls en cascada, verifica que la regla de VIP exista en cada salto; de lo contrario, el primer firewall puede reenviar al siguiente sin NAT y romper la ruta.
  • Cuando se usan certificados auto‑firmados, el cliente mostrará UNTRUSTED_ROOT. Eso es esperado; la prioridad es que el handshake se complete.
  • Si el firewall tiene SSL/SSH inspection, desactívala para la IP del VIP, ya que puede interceptar el handshake y devolver un reset.
  • Mantén los logs de HAProxy (log /dev/log local0) y de Keepalived (/var/log/syslog) a nivel debug mientras reproduces el fallo; la diferencia entre “no hay sesiones” y “sesiones cerradas” suele aparecer allí.