Come posso usare HAproxy con SSL e ottenere intestazioni X-Forwarded-For E dire a PHP che SSL è in uso?


20

Ho la seguente configurazione:

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

Per le richieste HTTP funziona alla grande , le richieste sono distribuite sui miei server Apache bene. Per le richieste SSL, avevo HAproxy che distribuiva le richieste usando il bilanciamento del carico TCP, e ha funzionato comunque poiché HAproxy non ha funzionato come proxy, non ha aggiunto l' X-Forwarded-Forintestazione HTTP e i server Apache / PHP non conoscevano il client indirizzo IP reale.

Quindi, ho aggiunto stunneldavanti a HAproxy, leggendo che lo stunnel potrebbe aggiungere l' X-Forwarded-Forintestazione HTTP. Tuttavia, il pacchetto che ho potuto installare in pfSense non aggiunge questa intestazione ... inoltre, questo apparentemente uccide la mia capacità di usare le richieste KeepAlive , che vorrei davvero conservare. Ma il problema più grande che ha ucciso quell'idea era che lo stunnel ha convertito le richieste HTTPS in semplici richieste HTTP, quindi PHP non sapeva che SSL era abilitato e ha cercato di reindirizzare al sito SSL.

Come posso usare HAproxy per bilanciare il carico su un numero di server SSL, consentendo a questi server sia di conoscere l'indirizzo IP del client sia di sapere che SSL è in uso? E se possibile, come posso farlo sul mio server pfSense?

O dovrei abbandonare tutto questo e usare solo nginx?


3
Ri: stunnel e X-Forwarded-For, vedi qui .
Shane Madden

@Shane: grazie. È esattamente dove ho letto che perdo KeepAlive :-)
Josh il

2
+1 per diagrammi ASCII eccellenti. :-)
KyleFarris,

@AlanHamlett, il tuo link è 404.
luckydonald

@luckydonald grazie, ecco un link aggiornato. È possibile utilizzare il protocollo proxy aggiungendo la parola chiave send-proxy alla configurazione haproxy. Ho scritto un post sul blog con esempi qui: wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
Alan Hamlett

Risposte:


17

Non è necessario lasciar perdere tutto, puoi semplicemente usare nginx davanti a haproxy per il supporto SSL, mantenendo tutta la configurazione del bilanciamento del carico. Non è nemmeno necessario utilizzare nginx per HTTP se non si desidera. Nginx può passare sia X-Forwarded-For sia un'intestazione personalizzata che indica che SSL è in uso (e, se lo si desidera, le informazioni sul certificato client). Snippet di configurazione Nginx che invia le informazioni richieste:

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;

37

Solo per la cronaca, poiché questo thread viene spesso indicato in merito a HAProxy + SSL, HAProxy supporta SSL nativo su entrambi i lati da 1.5-dev12. Quindi avere X-Forwarded-For, HTTP keep-alive così come un'intestazione che dice al server che la connessione è stata fatta tramite SSL è semplice come la seguente:

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 ...
    ...

Sono sicuro che quando avrai inventato qualcosa di diverso, ma almeno i nuovi visitatori avranno ora la soluzione semplice :-)


Grazie, questa è una buona informazione generale ... la mia domanda era su HAproxy in esecuzione su pfSense, quindi per ora devo usare nginx davanti a HAproxy, dato che pfSense non supporta questa versione di HAProxy (ancora)
Josh

Scusate Josh, non so abbastanza di pfSense per sapere se è possibile aggiornare i componenti su di esso o meno, e dal momento che stavate parlando dell'installazione di un pacchetto, ho pensato che fosse il caso. L'ultima volta che l'ho provato è stato circa 5 anni fa, quindi non ricordo tutti i dettagli.
Willy Tarreau,

1
Per ora non capisco molto sulla configurazione haproxy, ma con l'ultima versione, ho dovuto aggiungere un acl: acl is-ssl dst_port 443e riscrivere una riga: reqadd X-Forwarded-Proto:\ https if is-sslNginx sembra gestire abbastanza bene questa intestazione
greg0ire

Questo ha funzionato come un fascino. Nessun nginx richiesto.
Jay Taylor,

1
@greg0ire è perché con l'ultimo haproxy non c'è is_ssl ma ssl_fc invece
josch

12

Per chiunque abbia trovato questa domanda, ho seguito il consiglio di Ochoto e ho usato nginx. Ecco i passaggi specifici che ho usato per farlo funzionare sul mio router pfSense :

  1. Usando l'interfaccia web di pfsense , ho installato il pacchetto pfsense PfJailctl e il pacchetto "jail_template" in Sistema> Pacchetti in modo da poter creare una jail FreeBSD sotto la quale compilare e installare nginx sul sistema pfsense.

  2. Ho configurato una jail per il mio server nginx in Servizi> Jail , dando alla nuova jail lo stesso nome host e lo stesso indirizzo IP dell'alias IP virtuale su cui avevo in esecuzione HAproxy. Ho legato la prigione all'interfaccia WAN. Ho usato il modello jail predefinito e abilitato unionfs piuttosto che nullfs.

  3. Una volta che la prigione era stata avviata, sono entrato nella scatola pfsense e sono corso jlsa cercare il numero della prigione. Corsi quindi jexec 1 sha prendere una granata all'interno della prigione. Da lì ho impostato le porte BSD e installato nginx usando:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Ho quindi configurato nginx per l'ascolto sulla porta 443 e ho passato tutte le richieste a HAproxy sulla porta 80, incluso l'IP reale e lo stato SSL all'interno delle intestazioni HTTP. Il mio usr/local/etc/nginx/nginx.confaspetto è:

    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. Ho quindi modificato la mia applicazione PHP per rilevare l' X-Forwarded-Protointestazione HTTP:

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

Quindi l'installazione finale è:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]

2
È necessario disabilitare SSLv2 a meno che non sia realmente necessario. gnu.org/software/gnutls/manual/html_node/… Non so perché Nginx lo supporti ancora nella sua configurazione predefinita.
Ochoto,

Inoltre, ti rendi conto che con 1024 connessioni di lavoro supporterai al massimo 512 client simultanei.
Ochoto,

@Ochoto: grazie per entrambi questi consigli! Sono nuovo di HAproxy ma ancora meno familiare di nignx ...
Josh,

7

La mia configurazione per una versione 1.5-dev-17 di 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

Utilizza l' ssl_fcACL. Si noti che la option http-server-closeparte è molto importante.


Grazie! Sto eseguendo HAProxy v1.4, quindi non credo di poterlo fare, ma potrebbe aiutare gli altri.
Josh,

Sì, e l'1.5 dovrebbe essere presto disponibile.
Gregreg

5

HAProxy non può colpire un backend SSL senza usare la modalità TCP grezza, perdendo X-Forwarded-For, ma potresti potenzialmente ricrittografare il traffico con uno stunnel di ascolto per il transito di backend. Brutto, però.

Mi piace l'approccio di Ochoto meglio, con un avvertimento: nginx è un bilanciamento del carico perfettamente capace; se lo stai usando, direi di usarlo per tutto. Proxy del tuo HTTPS in arrivo per caricare back-end HTTPS bilanciati e, in questo modo, non sono necessarie intestazioni personalizzate per le informazioni SSL (a meno che non sia necessario il certificato client).


Non sono sicuro del motivo per cui mi sto aggrappando a HAproxy. Penso che sia perché pfSense ha un pacchetto per esso e SOIS lo usa. Nessuno dei due è un ottimo motivo. :-)
Josh,

Sto divagando da nginx diventando un capace bilanciamento del carico, a meno che tu non usi il modulo non standard upstream_fair che fa un semplice round robin (o client ip hash) senza tener conto se il backend di destinazione è già occupato con le richieste e quindi aumenta la coda in quel backend quando ci sono altri back-end gratuiti e in attesa di lavoro. HAProxy monitora bene anche i backend e mostra le statistiche su di essi.
Ochoto,

Se solo uno dei seguenti diventasse realtà a) Nginx ottiene un monitoraggio dello stato decente e un bilanciamento del carico equo b) HAProxy ottiene un supporto SSL decente Si può solo sperare
Yavor Shahpasov

Ho appena distribuito un setup usando nginx -> haproxy -> nginx -> backend per SSL, questo è dovuto alla mancanza del supporto HTTPS in haproxy come discusso qui, ma anche perché nginx non supporta gli script di controllo dello stato http.
Geoffrey,

2

L'anno scorso ho implementato una soluzione per integrare HAProxy con pfSense in modo da sfruttare tutte le funzionalità di HAProxy e mantenere un buon isolamento con pfSense. In modo che sia un'opzione praticabile per gli ambienti di produzione . SSL è terminato su HAProxy . Ho installato HAProxy in una jail in pfSense usando ezjail e Ports Collection . In questo modo è molto semplice mantenere entrambi i componenti in modo indipendente. E puoi installare qualunque versione tu voglia. Ho iniziato con 1.5-dev13. E da allora funziona perfettamente per me. Ho documentato il tutto qui.

Installazione di HAProxy su pfSense

A proposito Willy, grazie mille per un prodotto così eccellente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.