Recentemente, tentei configurar o roteamento baseado em SNI no HAProxy para mongodb+srv
conexão do protocolo mongodb.
Eu fiz funcionar, mas não foi até colocar
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
na minha configuração de frontend que começou a funcionar corretamente
Sem estes (oucom apenas umdestes) continuei recebendo redefinições de conexão esporádicas em cerca de 70% das minhas solicitações. Observe que em algum momento a conexão conseguiu ser estabelecida.
De acordo comhttp://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-tcp-request%20content
As regras baseadas em conteúdo são avaliadas na ordem exata de declaração. Se nenhuma regra corresponder ou se não houver nenhuma regra, a ação padrão será aceitar o conteúdo. Não há limite específico para o número de regras que podem ser inseridas.
Portanto, deveria estar funcionando por padrão.
Ou estou faltando algum conceito fundamental de TCP ou algum detalhe específico da conexão do Mongo. Mas percebi que quase todo mundo tem a mesma regra definida quando optam pelo roteamento baseado em SNI, então deve fazer sentido para a maioria das pessoas.
Configuração funcional do HAProxy:
frontend fe_mongo-nonprod
bind :27017
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net
use_backend be_mongo-nonprod if mongoAtlas-01 || mongoAtlas-02 || mongoAtlas-03
backend be_mongo-nonprod
mode tcp
acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net
use-server server-01 if mongoAtlas-01
use-server server-02 if mongoAtlas-02
use-server server-03 if mongoAtlas-03
server server-01 host1.mongodb.net:27017
server server-02 host2.mongodb.net:27017
server server-03 host3.mongodb.net:27017
Vale ressaltar também que o HAProxy é implantado no Kubernetes (cluster gerenciado pelo Google no GCP), possui um istio-sidecar e é exposto via serviço Internal LoadBalancer k8s.
Como afirmado, a configuração acima funciona perfeitamente bem. O que me interessa é por que tcp-request content accept
é absolutamente necessário e a conexão nem sempre é aceita por padrão aqui.
Responder1
Tentarei responder à minha própria pergunta depois de pensar um pouco.
Portanto, os documentos do HAProxy também têm a seguinte menção: http://cbonte.github.io/haproxy-dconv/2.0/configuration.html
Se for necessária a troca de conteúdo, é recomendado primeiro aguardar uma saudação completa do cliente (tipo 1), como no exemplo abaixo.
Agora, como os dados SNI também estão contidos na seção Client Hello da solicitação (https://www.rfc-editor.org/rfc/rfc6066#page-6) minha suposição é a seguinte:
No caso de o Client Hello estar espalhado por vários pacotes TCP e no tcp-request content accept is configured
, ao receber o primeiro pacote o HAProxy tenta roteá-lo e uma de duas coisas acontece:
- Se o back-end padrão estiver configurado, o pacote será encaminhado para esse back-end.
- Se nenhum back-end padrão estiver configurado (meu caso), o pacote será descartado e a conexão será redefinida.
Observe também que mesmo no primeiro caso descrito, o servidor HAProxy aponta na seção de back-end também pode exigir SNI. Portanto, encaminhar uma solicitação incompleta sem a indicação do SNI também resultará na redefinição da conexão.