Configurei o Keepalived como um balanceador de carga, mas não estou usando uma configuração Mestre/Standby, apenas um único servidor.
O problema surge quando o firewalld está habilitado. Sem o firewalld, tudo funciona bem. No entanto, quando o firewalld está em execução, os pacotes que retornam do servidor real são bloqueados com a regra STATE_INVALID_DROP.
A configuração envolve duas interfaces: enp2s0 (zona de clientes) e enp3s0 (zona de servidores). O tráfego fluindo de enp2s0 para enp3s0 funciona corretamente, mas o problema ocorre com o tráfego retornando de enp3s0 para enp2s0.
Curiosamente, se eu usar apenas firewalld com uma rota configurada para alcançar o servidor real e remover Keepalived, o tráfego flui sem problemas. O problema só aparece quando firewalld e Keepalived estão em uso juntos.
Esta é a minha configuração de zonas:
router1@router1:~$ sudo firewall-cmd --zone clients --list-all
clients (active)
target: DROP
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp2s0
sources:
services: http
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
router1@router1:~$ sudo firewall-cmd --zone servers --list-all
servers (active)
target: DROP
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp3s0
sources:
services: http
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
E esta é minha configuração política:
router1@router1:~$ sudo firewall-cmd --policy fromCliToSrv --list-all
fromCliToSrv (active)
priority: -1
target: DROP
ingress-zones: clients
egress-zones: servers
services: http
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
router1@router1:~$ sudo firewall-cmd --policy fromSrvToCli --list-all
fromSrvToCli (active)
priority: -1
target: DROP
ingress-zones: servers
egress-zones: clients
services: http
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
E esta é minha configuração keepalived:
router1@router1:~$ sudo cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
virtual_server 172.20.241.20 80 {
lb_algo wrr
lb_kind NAT
protocol TCP
persistence_timeout 600
persistence_granularity 255.255.255.0
real_server 10.0.1.5 {
weight 1
}
real_server 10.0.1.6 {
weight 2
}
real_server 10.0.1.7 {
weight 3
}
}
Tentei adicionar portas de encaminhamento à zona do cliente assim:
router1@router1:~$ sudo firewall-cmd --permanent --zone clients --add-forward-port=port=80:proto=tcp:toaddr=10.0.1.5:toport=80
success
router1@router1:~$ sudo firewall-cmd --permanent --zone clients --add-forward-port=port=80:proto=tcp:toaddr=10.0.1.6:toport=80
success
router1@router1:~$ sudo firewall-cmd --permanent --zone clients --add-forward-port=port=80:proto=tcp:toaddr=10.0.1.7:toport=80
success
router1@router1:~$ sudo firewall-cmd --reload
success
Mas esta configuração encaminha todas as solicitações para 10.0.1.5 porque é a primeira regra que foi adicionada
Isso ocorre devido ao modo como o keepalived funciona no modo NAT.
Ao usar NAT no keepalived, você está contando com regras do netfilter (iptables) para manipular os pacotes e fazer o balanceamento de carga (isso é efetivamente balanceamento de carga da camada 4).
O FirewallD também dita a política de tráfego usando netfilter (iptables) para bloquear partes específicas do tráfego.
Minha aposta é que ou o FirewallD destrói a configuração do netfilter keepalived ou vice-versa, ou a ordem e a prioridade das regras do netfilter tanto no keepalived quanto no FirewallD se somam de uma maneira que não faz sentido.
Em qualquer caso, sua solução mais pragmática aqui é não usar o FirewallD e criar diretamente quaisquer políticas de filtragem de rede usando
nft
ouiptables
diretamente com um conjunto de regras que não interfira no keepalived.Ou use um software balanceador de carga que apenas recria as conexões no próprio sistema, como o haproxy.
Eu também gostaria de ressaltar que os antigos módulos de balanceamento de carga do servidor virtual usados para keepalived (aquela
ipvsadm
coisa) não são compatíveis com o netfilter moderno (nft
baseado), pelo menos da última vez que tentei.Acabei relegando
keepalived
na minha mente como uma boa implementação de VRRP (failover), mas uma solução de balanceamento de carga ruim.Uma configuração comum é usar keepalived para failover e haproxy para balanceamento de carga. Essa configuração permite que você tenha seu bolo e ele também, deve haver bastante material online sobre como fazer isso manualmente, até mesmo imagens docker e outras opções de refeições prontas pré-assadas se você estiver com pressa.