Como posso usar o HAproxy com SSL e obter cabeçalhos X-Forwarded-For E dizer ao PHP que o SSL está em uso?

20

Eu tenho a seguinte configuração:

(internet) ---> [  pfSense Box  ]    /-> [ Apache / PHP server ]
                [running HAproxy] --+--> [ Apache / PHP server ]
                                    +--> [ Apache / PHP server ]
                                     \-> [ Apache / PHP server ]

Para solicitações HTTP, isso funciona muito bem , as solicitações são distribuídas para meus servidores Apache muito bem. Para solicitações SSL, eu tinha o HAproxy distribuindo as solicitações usando o balanceamento de carga TCP, e funcionou no entanto, uma vez que o HAproxy não agia como proxy, não adicionava o X-Forwarded-Forcabeçalho HTTP e os servidores Apache / PHP não conheciam o cliente. endereço IP real.

Então, eu adicionei stunnelna frente do HAproxy, ler esse stunnel poderia adicionar o X-Forwarded-Forcabeçalho HTTP. No entanto, o pacote que eu poderia instalar no pfSense não adiciona esse cabeçalho ... além disso, isso aparentemente mata minha capacidade de usar solicitações KeepAlive , que eu realmente gostaria de manter. Mas o maior problema que acabou com essa ideia foi que o stunnel converteu as solicitações HTTPS em solicitações HTTP simples, então o PHP não sabia que o SSL estava ativado e tentou redirecionar para o site SSL.

Como posso usar o HAproxy para carregar o equilíbrio em vários servidores SSL, permitindo que esses servidores saibam o endereço IP do cliente e saibam que o SSL está em uso? E, se possível, como posso fazer isso no meu servidor pfSense?

Ou devo largar tudo isso e usar o nginx?

Josh
fonte
3
Re: stunnel e X-Forwarded-For, veja aqui .
Shane Madden
@ Shane: Obrigado. Isso é exatamente onde eu li que eu perder KeepAlive :-)
Josh
2
+1 para excelente diagramação ASCII. :-)
KyleFarris
@AlanHamlett, sua ligação é 404.
luckydonald
@ luckydonald obrigado, aqui está um link atualizado. Você pode usar o Proxy Protocol adicionando a palavra-chave send-proxy à sua configuração haproxy. Eu escrevi um post com exemplos aqui: wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
Alan Hamlett

Respostas:

17

Você não precisa descartar tudo, basta usar o nginx na frente do haproxy para suporte a SSL, mantendo toda a sua configuração de balanceamento de carga. Você nem precisa usar o nginx para HTTP, se não quiser. O Nginx pode passar o X-Forwarded-For e um cabeçalho personalizado indicando que o SSL está em uso (e informações de certificação do cliente, se você desejar). Snippet de configuração do Nginx que envia as informações necessárias:

proxy_set_header SCHEME $scheme;      # http/https
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header CLIENT_CERT $ssl_client_raw_cert;
Ochoto
fonte
37

Apenas para constar, como esse encadeamento é frequentemente referido com relação ao HAProxy + SSL, o HAProxy suporta SSL nativo em ambos os lados desde o 1.5-dev12. Portanto, manter o X-Forwarded-For, HTTP keep-alive e um cabeçalho informando ao servidor que a conexão foi feita através de SSL é tão simples quanto o seguinte:

listen front
    bind :80
    bind :443 ssl crt /etc/haproxy/haproxy.pem
    mode http
    option http-server-close
    option forwardfor
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    server srv1 1.1.1.1:80 check ...
    ...

Tenho certeza de que, quando surgir algo diferente, mas pelo menos novos visitantes terão a solução mais fácil agora :-)

Willy Tarreau
fonte
Obrigado, esta é uma boa informação geral ... minha pergunta era sobre o HAproxy em execução no pfSense, então por enquanto ainda preciso usar o nginx na frente do HAproxy, pois o pfSense ainda não suporta esta versão do HAProxy (
Josh
Desculpe Josh, eu não sei o suficiente sobre o pfSense para saber se você pode atualizar os componentes ou não, e como você estava falando sobre a instalação de um pacote, eu acreditava que era o caso. A última vez que tentei foi há cerca de 5 anos, por isso não me lembro de todos os detalhes.
Willy Tarreau 26/09/12
11
Eu não entendo muito sobre configuração haproxy por agora, mas com a versão mais recente, eu tive que adicionar uma ACL: acl is-ssl dst_port 443e reescrever uma linha: reqadd X-Forwarded-Proto:\ https if is-sslNginx parece lidar com este cabeçalho razoavelmente bem
greg0ire
Isso funcionou como um encanto. Não é necessário nginx.
Jay Taylor
11
@ greg0ire Isso porque com o mais recente haproxy não há is_ssl mas ssl_fc vez
Josch
12

Para quem encontrar essa pergunta, segui o conselho de Ochoto e usei o nginx. Aqui estão as etapas específicas que eu usei para fazer isso funcionar no meu roteador pfSense :

  1. Usando a interface da web pfsense , instalei o pacote pfsense PfJailctl e o pacote "jail_template" em Sistema> Pacotes para criar uma prisão do FreeBSD na qual compilar e instalar o nginx no sistema pfsense.

  2. Configurei uma cadeia para o meu servidor nginx em Serviços> Cadeias , fornecendo à nova cadeia o mesmo nome de host e endereço IP do alias de IP virtual no qual o HAproxy estava sendo executado. Liguei a prisão à interface da WAN. Eu usei o modelo de prisão padrão e habilitei unionfs em vez de nullfs.

  3. Depois que a prisão foi iniciada, eu entrei na caixa do pfsense e corri jlspara encontrar o número da prisão. Eu corri jexec 1 shpara pegar uma concha dentro da prisão. A partir daí, configurei as portas BSD e instalei o nginx usando:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Em seguida, configurei o nginx para escutar na porta 443 e passar todas as solicitações para o HAproxy na porta 80, incluindo o IP real e o status SSL nos cabeçalhos HTTP. Minha usr/local/etc/nginx/nginx.confaparência é:

    worker_processes  1;
    
    events {
        worker_connections  2048;
    }
    
    http {
        upstream haproxy {
            server 209.59.186.35:80;
        }
    
        server {
            listen       443;
            server_name  my.host.name default_server;
            ssl                  on;
            ssl_certificate      my.crt;
            ssl_certificate_key  my.key;
            ssl_session_timeout  5m;
    
            ssl_protocols  SSLv3 TLSv1;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers   on;
    
            location / {
                proxy_pass http://haproxy;
    
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
                proxy_set_header X-Forwarded-Proto https;
            }
        }
    
    }
    
  5. Modifiquei meu aplicativo PHP para detectar o X-Forwarded-Protocabeçalho HTTP:

    function usingSSL()
    {
        return (
           (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' )
            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
                   && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' ));
    }
    

Portanto, a configuração final é:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]
Josh
fonte
2
Você deve desativar o SSLv2, a menos que realmente precise. gnu.org/software/gnutls/manual/html_node/… Não sei por que o Nginx ainda o suporta em sua configuração padrão.
Ochoto 18/08/11
Perceba também que, com 1024 conexões de trabalho, você oferecerá suporte a no máximo 512 clientes simultâneos.
Ochoto 18/08/11
@Ochoto: Obrigado por essas duas dicas! Eu sou novo para HAProxy mas ainda menos familiarizados com nignx ...
Josh
7

Minha configuração para uma versão 1.5-dev-17 do haproxy:

global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        #log loghost    local0 info
        maxconn 4096
        #chroot /usr/share/haproxy
        user haproxy
        group haproxy
        daemon
        #debug
        #quiet

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  http-server-close
        retries 3
        option redispatch
        fullconn 1000        
        maxconn 1000
        timeout queue 600s
        timeout connect 5s
        timeout client 600s
        timeout server 600s

frontend http-in
        bind *:80
        bind *:443 ssl crt /usr/local/etc/ssl/certs
        reqadd X-Forwarded-Proto:\ https if { ssl_fc }
        default_backend varnish-ha
        option forwardfor
backend varnish-ha
  server hafront1 10.1.69.1:6081  minconn 100 maxqueue 10000

Ele usa a ssl_fcACL. Observe que a option http-server-closepeça é muito importante.

greg0ire
fonte
Obrigado! Estou executando o HAProxy v1.4, então não acho que posso fazer isso, mas isso pode ajudar outras pessoas.
21713 Josh
Sim, e o 1.5 deve sair em breve.
greg0ire
5

O HAProxy não pode atingir um back-end SSL sem usar o modo TCP bruto, perdendo X-Forwarded-For, mas você pode potencialmente criptografar novamente o tráfego com um stunnel de escuta para o trânsito de back-end. Feio, no entanto.

Gosto mais da abordagem de Ochoto, com uma ressalva: o nginx é um balanceador de carga perfeitamente capaz; se você estiver usando, eu diria que use para tudo. Proxy seu HTTPS de entrada para carregar back-end HTTPS balanceados - e, dessa forma, não há necessidade de cabeçalhos personalizados para informações SSL (a menos que você precise do certificado do cliente).

Shane Madden
fonte
Não sei por que estou me apegando ao HAproxy. Eu acho que é porque o pfSense tem um pacote e o SOIS o usa. Nenhum dos dois é um ótimo motivo. :-)
Josh
Discordo do nginx sendo um balanceador de carga capaz, a menos que você use o módulo upstream_fair não padrão, ele executa um round robin simples (ou hash de IP do cliente) sem levar em conta se o back-end de destino já está ocupado com solicitações e, assim, aumenta a fila nesse back-end quando existem outros back-end gratuitos e esperando um emprego. O HAProxy também monitora bem os back-ends e exibe estatísticas sobre eles.
Ochoto 18/08/11
Se apenas um dos seguintes se tornaria verdadeira a) Nginx recebe rastreamento estado decente e carga justo equilíbrio b) HAProxy recebe apoio SSL decente Só se pode esperança
Yavor Shahpasov
Acabei de implantar uma configuração usando o nginx -> haproxy -> nginx -> back-end para SSL, devido à falta de suporte HTTPS no haproxy, conforme discutido aqui, mas também porque o nginx não suporta scripts de verificação de integridade http.
Geoffrey
2

Eu implementei uma solução no ano passado para integrar o HAProxy ao pfSense , de forma a aproveitar todos os recursos do HAProxy e manter um bom isolamento com o pfSense. Para que seja uma opção viável para ambientes de produção . O SSL é encerrado no HAProxy . Instalei o HAProxy dentro de uma prisão no pfSense usando o ezjail e o Ports Collection . Dessa forma, é muito fácil manter os dois componentes independentemente. E você pode instalar a versão que desejar. Comecei com 1.5-dev13. E desde então está funcionando perfeitamente para mim. Eu documentei a coisa toda aqui.

Instalando o HAProxy no pfSense

Aliás, Willy, muito obrigado por um produto tão excelente.

Dinesh Sharma
fonte