Posso usar o novo recurso 'capture' do HAProxy para salvar o endereço remoto em um frontend TCP, e usá-lo como o cabeçalho 'X-Forwarded-For' em um backend HTTP?

6

Uso do HAProxy 1.6 e de um hack inteligente , agora eu tenho um frontend do modo HAProxy tcp, que detecta se o navegador é capaz de SNI e, com base nisso, direciona para um backend de terminação SSL strongmente cifrado, ou um mais fraco. Isso garante classificação A + em laboratórios SSL, enquanto ainda permite que todos os navegadores, exceto o IE6, usem SSL.

Aqui está minha configuração. Ele tem algumas variáveis de gabarito que devem ser autoexplicativas, mas não estão em áreas relevantes para minha pergunta:

frontend https_incoming
 bind 0.0.0.0:443
 mode tcp
 option tcplog
 tcp-request inspect-delay 5s
 tcp-request content accept if { req.ssl_hello_type 1 }
 use_backend https_strong if { req.ssl_sni -m end .transloadit.com }
 default_backend https_weak

backend https_strong
 mode tcp
 option tcplog
 server https_strong 127.0.0.1:1665

frontend https_strong
 bind 127.0.0.1:1665 ssl crt ${DM_ROOT_DIR}/envs/ssl/haproxy-dh2048.pem no-sslv3 no-tls-tickets ciphers ${strongCiphers}
 mode http
 option httplog
 option httpclose
 option forwardfor if-none except 127.0.0.1
 http-response add-header Strict-Transport-Security max-age=31536000
 reqadd X-Forwarded-Proto:\ https
 reqadd FRONT_END_HTTPS:\ on
 use_backend http_incoming

backend https_weak
 mode tcp
 option tcplog
 server https_weak 127.0.0.1:1667

frontend https_weak
 bind 127.0.0.1:1667 ssl crt ${DM_ROOT_DIR}/envs/ssl/haproxy.pem no-sslv3 ciphers ${weakCiphers}
 mode http
 option httplog
 option httpclose
 option forwardfor if-none except 127.0.0.1
 http-response add-header Strict-Transport-Security max-age=31536000
 reqadd X-Forwarded-Proto:\ https
 reqadd FRONT_END_HTTPS:\ on
 use_backend http_incoming

Problema: o https_incoming frontend conhece o IP do cliente, mas como está em mode tcp , ele não pode salvar essas informações em um mode http X-Forwarded-For header. option forwardfor não é válido no modo TCP.

De outra questão no serverfault Eu já achei que poderia usar:

  • LVS
  • protocolo PROXY

Para que o cabeçalho X-Forwarded-For não seja mais necessário, pelo que entendi, no caso do LVS: os pacotes são falsificados, portanto, a origem se torna o IP do cliente e, no caso de PROXY: os pacotes são encapsulados levar o IP do cliente.

Estes dois parecem que podem funcionar. O LVS, no entanto, parece bastante uma cirurgia cardíaca para nós que poderia ter efeitos colaterais, e o PROXY tem a desvantagem de que os proxies / aplicativos upstream / downstream, podem não ser totalmente compatíveis ainda.

Eu estava realmente esperando por algo mais leve, e foi aí que eu encontrei o novo Recurso" Capture "do HAProxy 1.6 como mencionado:

you can declare capture slots, store data in it and use it at any time during a session.

continua mostrando o seguinte exemplo:

defaults 
 mode http

frontend f_myapp
 bind :9001
 declare capture request len 32 # id=0 to store Host header
 declare capture request len 64 # id=1 to store User-Agent header
 http-request capture req.hdr(Host) id 0
 http-request capture req.hdr(User-Agent) id 1
 default_backend b_myapp

backend b_myapp
 http-response set-header Your-Host %[capture.req.hdr(0)]
 http-response set-header Your-User-Agent %[capture.req.hdr(1)]
 server s1 10.0.0.3:4444 check

Parece-me que as informações são armazenadas em um frontend e usadas posteriormente em um backend, então talvez eu possa pegar o IP do cliente no modo TCP, salvá-lo e usá-lo mais tarde, talvez assim:

http-response set-header X-Forwarded-For %[capture.req.hdr(0)]

Eu examinei os documentos de captura e parece que a captura é mais orientada para os cabeçalhos do modo http, mas também vi uma conversa na lista de discussão que demonstre com sucesso o uso de um tcp-request capture .

Eu tentei várias coisas, entre as quais:

tcp-request capture req.hdr(RemoteAddr) id 0
# or
tcp-request content capture req.hdr(RemoteHost) id 0

Mas, como você pode ver, eu não entendi qual deveria ser a sintaxe e sob qual chave essa informação estaria disponível, nem posso encontrá-la em a (eu acho) documentação relevante .

Perguntas: Seria possível capturar o IP do cliente no modo TCP e, mais tarde, escrever essas informações no cabeçalho X-Forwarded-For no modo HTTP? Se sim, qual seria a sintaxe para isso?

    
por kvz 09.07.2016 / 11:20

2 respostas

3

Para responder a minha própria pergunta, isso não parece possível, pois o tráfego "deixa" o HAProxy aqui:

       TCP                             HTTP
frontend->backend (->leaving->) frontend->backend

Assim, o contexto é perdido e a captura não pode ser preservada. Em vez disso, como "PiBa-NL" sugerido no IRC no #haproxy na Freenode ontem:

[5:29pm] PiBa-NL: kvz, use proxy-protocol between back and front
[5:54pm] kvz: PiBa-NL: Thanks, does this mean my app also needs to understand 
         the proxy protocol, or will it be 'stripped' once it reaches the 
         backend. I don't think my node.js server could handle it without  
         significant changes to its stack
[6:07pm] kvz: Or let me rephrase: could I enable the proxy protocol on the first 
         frontend, then 'unwrap' it in the second frontend, taking the client ip 
         and putting it into the http header - so that my app would not have to 
         be proxy protocol compatible, and it would just be means to carry the 
         client ip from first frontend to the second?
[6:49pm] PiBa-NL: kvz, the last part you can still use the x-forwarded-for header
[6:50pm] PiBa-NL: but between haproxy backend and frontend you would use the 
         proxyprotocol to make the second frontent 'know' the original client ip
[6:50pm] PiBa-NL: server https_strong 127.0.0.1:1665 send-proxy
[6:50pm] PiBa-NL: bind 127.0.0.1:1665 ssl crt .... accept-proxy
[6:52pm] PiBa-NL: the second frontend can then still use the  
         'option forwardfor', and it should insert the wanted header
[6:53pm] PiBa-NL: so basically 'yes' 

Isso significa que o protocolo PROXY é usado apenas para colar os dois frontends juntos, encapsulando o Cient IP, mas o segundo frontend o desembrulha e o salva no X-Forwarded-For header via option forwardfor , para que seu backend possa enviar um Pedido sem protocolo PROXY para o meu servidor de aplicações, o que significa que não tenho de me preocupar com problemas de compatibilidade up / downstream.

    
por 11.07.2016 / 09:31
0

O HAProxy já deveria estar adicionando o cabeçalho X-Forwarded-For. Você pode querer adicionar protocolo e / ou porta se algum deles não for padrão.

Eu geralmente testo esse tipo de comportamento com uma página que ecoa os cabeçalhos da solicitação. Isso torna mais fácil ver quais cabeçalhos estão disponíveis e quais são seus conteúdos.

Não é incomum que o X-Forward-For contenha uma lista de endereços. Isso sinaliza que a solicitação passou por vários proxies ou que alguém está falsificando o cabeçalho. O endereço mais correto será aquele que foi adicionado pelo último proxy (ha-proxy) que tratou da solicitação.

Alguns servidores da web podem ser configurados para registrar um endereço IP de um cabeçalho em vez da conexão. Isso seria útil para seus logs de acesso e um caso em que você desejaria gerar um cabeçalho com base no endereço IP de conexões de entrada.

É possível obter uma classificação A + enquanto suporta todos os navegadores listados, exceto o IE 6 Sem usar duas pilhas diferentes.

  • Para o Java 6, desative pelo menos DHE-RSA-AES128-SHA e AES128-SHA. É possivelmente todas as cifras sem sigilo antecipado.
  • Para WinXP / IE8 e Java6, ative o DES-CBC3-SHA e / ou o EDH-DSS-DES-CBC3-SHA. Estas devem ser as cifras menos preferidas, pois não suportam o sigilo antecipado.

O WinXP / IE8 e o Java 6 não suportam o Encaminhamento para a frente com um protocolo seguro, portanto, o teste não penaliza a sua falha. Todos os outros navegadores usarão sigilo antecipado se você forçar a ordenação do servidor. (Win Phones falhará se você não o fizer.)

Uma classificação de A + requer a configuração de Segurança de transporte estrito com um período de pelo menos 180 dias.

    
por 09.07.2016 / 18:16