Jak mogę używać HAproxy z SSL i uzyskać nagłówki X-Forwarded-For ORAZ powiedzieć PHP, że SSL jest w użyciu?

20

Mam następującą konfigurację:

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

W przypadku żądań HTTP działa to świetnie , żądania są dobrze dystrybuowane na moje serwery Apache. W przypadku żądań SSL HAproxy dystrybuował żądania za pomocą równoważenia obciążenia TCP i działał jednak, ponieważ HAproxy nie działał jako serwer proxy, nie dodał X-Forwarded-Fornagłówka HTTP, a serwery Apache / PHP nie znały klienta prawdziwy adres IP.

Dodałem więc stunnelprzed HAproxy, czytając, że stunnel może dodać X-Forwarded-Fornagłówek HTTP. Jednak pakiet, który mogłem zainstalować w pfSense, nie dodaje tego nagłówka ... to najwyraźniej zabija moją zdolność do korzystania z żądań KeepAlive , którą naprawdę chciałbym zachować. Ale największym problemem, który zabił ten pomysł, było to, że stunnel przekształcił żądania HTTPS w zwykłe żądania HTTP, więc PHP nie wiedział, że SSL jest włączony i próbował przekierować na stronę SSL.

Jak mogę użyć HAproxy, aby załadować równowagę między wieloma serwerami SSL, pozwalając tym serwerom zarówno znać adres IP klienta, jak i wiedzieć, że SSL jest używany? A jeśli to możliwe, jak mogę to zrobić na moim serwerze pfSense?

Czy powinienem to wszystko porzucić i po prostu użyć nginx?

Josh
źródło
3
Re: stunnel i X-Forwarded-Forpatrz tutaj .
Shane Madden
@Shane: Dzięki. Właśnie tam czytam, że tracę KeepAlive :-)
Josh
2
+1 za doskonałe tworzenie diagramów ASCII. :-)
KyleFarris,
@AlanHamlett, twój link to 404.
luckydonald
@luckydonald dzięki, oto zaktualizowany link. Możesz użyć protokołu proxy, dodając słowo kluczowe send-proxy do konfiguracji haproxy. Napisałem post na blogu z przykładami tutaj: wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
Alan Hamlett

Odpowiedzi:

17

Nie musisz upuszczać wszystkiego, możesz po prostu użyć nginx przed haproxy do obsługi SSL, zachowując całą konfigurację równoważenia obciążenia. Nie musisz nawet używać nginx dla HTTP, jeśli nie chcesz. Nginx może przekazać zarówno X-Forwarded-For, jak i niestandardowy nagłówek wskazujący, że SSL jest w użyciu (i informacje o certyfikacie klienta, jeśli chcesz). Fragment konfiguracji Nginx, który wysyła wymagane informacje:

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
źródło
37

Dla przypomnienia, ponieważ ten wątek jest często przywoływany w odniesieniu do HAProxy + SSL, HAProxy obsługuje natywne SSL po obu stronach od 1.5-dev12. Posiadanie X-Forwarded-For, HTTP keep-alive, a także nagłówek informujący serwer, że połączenie zostało nawiązane przez SSL, jest tak proste, jak to:

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

Jestem pewien, że zanim wymyślisz coś innego, ale przynajmniej nowi goście otrzymają teraz łatwe rozwiązanie :-)

Willy Tarreau
źródło
Dzięki, to są dobre ogólne informacje ... moje pytanie dotyczyło HAproxy działającego na pfSense, więc na razie muszę używać nginx przed HAproxy, ponieważ pfSense nie obsługuje tej wersji HAProxy (jeszcze)
Josh
Przepraszamy Josh, nie wiem wystarczająco dużo o pfSense, aby wiedzieć, czy możesz zaktualizować na nim składniki, czy nie, a ponieważ mówiłeś o instalacji pakietu, wierzyłem, że tak jest. Ostatni raz próbowałem to około 5 lat temu, więc nie pamiętam wszystkich szczegółów.
Willy Tarreau,
1
Na razie nie rozumiem wiele na temat konfiguracji haproxy, ale w najnowszej wersji musiałem dodać acl: acl is-ssl dst_port 443i przepisać wiersz: reqadd X-Forwarded-Proto:\ https if is-sslNginx wydaje się dość dobrze obsługiwać ten nagłówek
greg0ire
To działało jak urok. Nie wymaga nginx.
Jay Taylor
1
@ greg0ire to dlatego, że w najnowszym haproxy nie ma is_ssl, ale zamiast tego
ssl_fc
12

Dla każdego, kto znajdzie to pytanie, zastosowałem się do rady Ochoto i użyłem nginx. Oto konkretne kroki, które zastosowałem, aby to zadziałało na moim routerze pfSense :

  1. Korzystając z interfejsu internetowego pfsense, zainstalowałem pakiet pfsense PfJailctl i pakiet „jail_template” w obszarze System> Pakiety, dzięki czemu mogłem stworzyć więzienie FreeBSD, na podstawie którego skompiluję i zainstaluję nginx w systemie pfsense.

  2. Skonfigurowałem więzienie dla mojego serwera nginx w obszarze Usługi> Więzienia , nadając nowemu więzieniu tę samą nazwę hosta i adres IP wirtualnego aliasu IP, na którym działałem HAproxy. Związałem więzienie z interfejsem WAN. Użyłem domyślnego szablonu więzienia i włączyłem unionfs zamiast nullfs.

  3. Po rozpoczęciu więzienia włączyłem SSF do skrzynki pfsense i pobiegłem jlsznaleźć numer więzienia. Potem pobiegłem jexec 1 shpo skorupę do więzienia. Stamtąd skonfigurowałem porty BSD i zainstalowałem nginx, używając:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Następnie skonfigurowałem nginx do nasłuchiwania na porcie 443 i przekazałem wszystkie żądania do HAproxy na porcie 80, w tym rzeczywiste IP i status SSL w nagłówkach HTTP. Mój usr/local/etc/nginx/nginx.confwygląda jak:

    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. Następnie zmodyfikowałem aplikację PHP, aby wykryła X-Forwarded-Protonagłówek HTTP:

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

Ostateczna konfiguracja to:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]
Josh
źródło
2
Powinieneś wyłączyć SSLv2, chyba że naprawdę go potrzebujesz. gnu.org/software/gnutls/manual/html_node/… Nie wiem, dlaczego Nginx nadal obsługuje go w domyślnej konfiguracji.
Ochoto,
Pamiętaj również, że przy 1024 połączeniach roboczych będziesz obsługiwać maksymalnie 512 równoczesnych klientów.
Ochoto,
@Ochoto: Dzięki za obie te wskazówki! Jestem nowy w HAproxy, ale jeszcze mniej znam nignx ...
Josh
7

Moja konfiguracja dla wersji haproxy 1.5-dev-17:

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

Korzysta z ssl_fcACL. Pamiętaj, że ta option http-server-closeczęść jest bardzo ważna.

greg0ire
źródło
Dzięki! Korzystam z HAProxy v1.4, więc nie sądzę, że mogę to zrobić, ale może to pomóc innym.
Josh
Tak, a 1.5 powinno być wkrótce dostępne.
greg0ire,
5

HAProxy nie może trafić do backendu SSL bez użycia surowego trybu TCP, tracąc X-Forwarded-For, ale możesz potencjalnie ponownie zaszyfrować ruch za pomocą stunnela nasłuchującego na potrzeby tranzytu backendu. Ale brzydkie.

Bardziej podoba mi się podejście Ochoto, z zastrzeżeniem: nginx jest doskonale zdolnym równoważeniem obciążenia; jeśli go używasz, powiedziałbym, że używaj go do wszystkiego. Proxy swojego przychodzącego HTTPS, aby załadować zrównoważone zaplecze HTTPS - w ten sposób nie ma potrzeby niestandardowych nagłówków dla informacji SSL (chyba że potrzebujesz certyfikatu klienta).

Shane Madden
źródło
Nie jestem pewien, dlaczego trzymam się HAproxy. Myślę, że to dlatego, że pfSense ma dla niego pakiet, a SOIS go używa. Żaden z nich nie jest doskonałym powodem. :-)
Josh
Odchodzę od nginx, który jest w stanie wyrównać obciążenie, chyba że użyjesz niestandardowego modułu upstream_fair, robi to prosty okrągły robin (lub skrót IP klienta) bez uwzględnienia, czy backend docelowy jest już zajęty żądaniami, a tym samym rosnącą kolejką w tym backendie, gdy istnieją inne backendy darmowe i czekają na pracę. HAProxy również ładnie monitoruje backendy i wyświetla statystyki na ich temat.
Ochoto,
Gdyby spełniony był tylko jeden z poniższych warunków: a) Nginx otrzymuje przyzwoite śledzenie stanu i sprawiedliwe równoważenie obciążenia b) HAProxy otrzymuje przyzwoitą obsługę SSL Można mieć tylko nadzieję
Jawor Szahpasow
Właśnie wdrożyłem instalację przy użyciu nginx -> haproxy -> nginx -> backend dla SSL, jest to spowodowane brakiem obsługi HTTPS w haproxy, jak omówiono tutaj, ale także dlatego, że nginx nie obsługuje skryptów sprawdzania kondycji http.
Geoffrey
2

W zeszłym roku wdrożyłem rozwiązanie integrujące HAProxy z pfSense w taki sposób, że wykorzystuje ono wszystkie funkcje HAProxy i utrzymuje dobrą izolację z pfSense. Dzięki temu jest to opłacalna opcja dla środowisk produkcyjnych . Protokół SSL zostaje zakończony w HAProxy . Zainstalowałem HAProxy w więzieniu w pfSense za pomocą ezjail i Ports Collection . W ten sposób bardzo łatwo można niezależnie utrzymywać oba komponenty. Możesz zainstalować dowolną wersję. Zacząłem od 1.5-dev13. I od tego czasu działa idealnie dla mnie. Udokumentowałem to wszystko tutaj.

Instalowanie HAProxy na pfSense

BTW Willy, wielkie dzięki za tak doskonały produkt.

Dinesh Sharma
źródło