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

19

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 ótimo , as solicitações são distribuídas para os meus servidores Apache muito bem. Para solicitações SSL, tive o HAoxyy distribuindo as solicitações usando o balanceamento de carga TCP, e funcionou no entanto, já que o HAproxy não atuou como um proxy, não adicionou o cabeçalho X-Forwarded-For HTTP e os servidores Apache / PHP não conheça o endereço IP real do cliente.

Então, eu adicionei stunnel na frente do HAproxy, lendo que o stunnel poderia adicionar o X-Forwarded-For HTTP header. No entanto, o pacote que eu pude instalar no pfSense não adiciona esse cabeçalho ... também, isso aparentemente mata meu capacidade de usar solicitações KeepAlive , o que eu realmente gostaria de manter. Mas o maior problema que matou 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 habilitado e tentou redirecionar para o site SSL.

Como posso usar o HAproxy para balancear a carga em vários servidores SSL, permitindo que esses servidores conheçam o endereço IP do cliente e sabem que o SSL está em uso? E, se possível, como posso fazê-lo no meu servidor pfSense?

Ou devo largar tudo isso e usar o nginx?

    
por Josh 17.08.2011 / 23:08

6 respostas

16

Você não precisa desistir de tudo, você poderia apenas usar o nginx na frente do haproxy para suporte 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 customizado indicando que o SSL está em uso (e as informações do certificado do cliente, se desejar). Snippet de configuração 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;
    
por 17.08.2011 / 23:38
34

Apenas para o registro, como este encadeamento é frequentemente referido em relação ao HAProxy + SSL, o HAProxy suporta SSL nativo em ambos os lados desde o 1.5-dev12. Então, ter X-Forwarded-For, HTTP keep-alive, assim como um cabeçalho informando ao servidor que a conexão foi feita via 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 no momento em que você surgiu algo diferente, mas pelo menos novos visitantes terão a solução mais fácil agora: -)

    
por 16.09.2012 / 10:35
11

Para qualquer outra pessoa que encontre essa pergunta, eu segui o conselho de Ochoto e usei o nginx. Aqui estão os passos específicos que eu usei para fazer isso funcionar no meu roteador pfSense :

  1. Usando a interface da Web pfsense, instalei o pacote PfJailctl e o pacote "jail_template" do pfsense em Sistema > Pacotes para que eu possa criar uma cadeia do FreeBSD sob a qual compilar e instalar o nginx no sistema pfsense.

  2. Eu configurei uma cadeia para o meu servidor nginx em Serviços > Jails , dando à nova cadeia o mesmo nome de host e endereço IP do alias de IP virtual em que eu tinha o HAproxy em execução. Liguei a cadeia à interface WAN. Eu usei o modelo de cadeia padrão e ative unionfs em vez de nullfs.

  3. Uma vez que a prisão foi iniciada, eu entrei na caixa pfsense e corri jls para encontrar o número da prisão. Eu então corri jexec 1 sh para obter uma concha dentro da cadeia. De lá eu configurei as portas BSD e instalei o nginx usando:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Eu configurei o nginx para escutar na porta 443 e passar todos os pedidos para o HAproxy na porta 80, incluindo o IP real e o status do SSL dentro dos cabeçalhos HTTP. Meu usr/local/etc/nginx/nginx.conf se parece com:

    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. Eu modifiquei meu aplicativo PHP para detectar o X-Forwarded-Proto HTTP Header:

    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)  ]
    
por 18.08.2011 / 17:17
5

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 o ssl_fc ACL. Por favor, note que a parte option http-server-close é muito importante.

    
por 15.01.2013 / 11:58
4

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

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

    
por 17.08.2011 / 23:48
1

Eu implementei uma solução no ano passado para integrar o HAProxy com o pfSense de forma que aproveite todos os recursos do HAProxy e mantenha um bom isolamento com o pfSense. Por isso, é uma opção viável para ambientes de produção . O SSL é terminado em HAProxy . Eu instalei o HAProxy dentro de uma cadeia no pfSense usando ezjail e Ports Collection . Dessa forma, é muito fácil manter os dois componentes independentemente. E você pode instalar qualquer versão que quiser. Eu 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

BTW Willy, muito obrigado por um produto tão excelente.

    
por 29.04.2013 / 15:15