Bagaimana saya bisa menggunakan HAproxy dengan SSL dan mendapatkan header X-Forwarded-For DAN memberi tahu PHP bahwa SSL sedang digunakan?

20

Saya memiliki pengaturan berikut:

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

Untuk permintaan HTTP ini berfungsi dengan baik , permintaan didistribusikan ke server Apache saya dengan baik. Untuk permintaan SSL, saya meminta HAproxy mendistribusikan permintaan menggunakan penyeimbangan beban TCP, dan itu berhasil karena HAproxy tidak bertindak sebagai proxy, itu tidak menambahkan X-Forwarded-Forheader HTTP, dan server Apache / PHP tidak tahu klien alamat IP asli.

Jadi, saya menambahkan stunneldi depan HAproxy, membaca bahwa stunnel dapat menambahkan X-Forwarded-Forheader HTTP. Namun, paket yang saya dapat instal ke pfSense tidak menambahkan header ini ... juga, ini tampaknya membunuh kemampuan saya untuk menggunakan permintaan KeepAlive , yang ingin saya simpan. Tetapi masalah terbesar yang mematikan gagasan itu adalah bahwa stunnel mengubah permintaan HTTPS menjadi permintaan HTTP biasa, jadi PHP tidak tahu bahwa SSL diaktifkan dan mencoba mengalihkan ke situs SSL.

Bagaimana saya bisa menggunakan HAproxy untuk memuat saldo di sejumlah server SSL, memungkinkan server-server itu untuk mengetahui alamat IP klien dan mengetahui bahwa SSL sedang digunakan? Dan jika mungkin, bagaimana saya bisa melakukannya di server pfSense saya?

Atau haruskah saya menghentikan semua ini dan hanya menggunakan nginx?

Josh
sumber
3
Re: stunnel and X-Forwarded-For, lihat di sini .
Shane Madden
@Shane: Terima kasih. Di situlah saya membaca bahwa saya kehilangan KeepAlive :-)
Josh
2
+1 untuk diagram ASCII yang sangat baik. :-)
KyleFarris
@AlanHamlett, tautan Anda adalah 404.
luckydonald
@luckydonald terima kasih, ini tautan yang diperbarui. Anda dapat menggunakan Protokol Proksi dengan menambahkan kata kunci send-proxy ke konfigurasi haproxy Anda. Saya menulis posting blog dengan contoh di sini: wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
Alan Hamlett

Jawaban:

17

Anda tidak perlu membatalkan semuanya, Anda bisa menggunakan nginx di depan haproxy untuk dukungan SSL, menjaga semua konfigurasi balancing Anda. Anda bahkan tidak perlu menggunakan nginx untuk HTTP jika Anda tidak mau. Nginx dapat melewati X-Forwarded-For dan header khusus yang menunjukkan SSL sedang digunakan (dan informasi klien jika Anda mau). Cuplikan konfigurasi nginx yang mengirimkan informasi yang diperlukan:

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
sumber
37

Sebagai catatan, karena utas ini sering disebut tentang HAProxy + SSL, HAProxy mendukung SSL asli di kedua sisi sejak 1.5-dev12. Jadi memiliki X-Forwarded-For, HTTP keep-live serta header yang memberitahu server bahwa koneksi dilakukan melalui SSL adalah sesederhana berikut ini:

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

Saya yakin bahwa pada saat Anda datang dengan sesuatu yang berbeda, tetapi setidaknya pengunjung baru akan mendapatkan solusi mudah sekarang :-)

Willy Tarreau
sumber
Terima kasih, ini info umum yang bagus ... pertanyaan saya adalah tentang HAproxy yang berjalan di pfSense jadi untuk sekarang saya masih perlu menggunakan nginx di depan HAproxy, karena pfSense tidak mendukung versi HAProxy ini (
Josh)
Maaf Josh, saya tidak cukup tahu tentang pfSense untuk mengetahui apakah Anda dapat memperbarui komponen di dalamnya atau tidak, dan karena Anda berbicara tentang menginstal sebuah paket, saya yakin itulah masalahnya. Terakhir kali saya mencobanya sekitar 5 tahun yang lalu, jadi saya tidak ingat semua detailnya.
Willy Tarreau
1
Saya tidak mengerti banyak tentang konfigurasi haproxy untuk saat ini, tetapi dengan versi terbaru, saya harus menambahkan sebuah acl: acl is-ssl dst_port 443dan menulis ulang sebuah baris: reqadd X-Forwarded-Proto:\ https if is-sslNginx tampaknya menangani header ini dengan cukup baik
greg0ire
Ini bekerja seperti pesona. Tidak diperlukan nginx.
Jay Taylor
1
@ greg0ire itu karena dengan haproxy terbaru tidak ada is_ssl tetapi ssl_fc sebagai gantinya
josch
12

Untuk siapa pun yang menemukan pertanyaan ini, saya mengikuti saran Ochoto dan menggunakan nginx. Inilah langkah-langkah spesifik yang saya gunakan untuk membuat ini bekerja di router pfSense saya :

  1. Menggunakan antarmuka web pfsense, saya menginstal paket PfJailctl pfsense dan paket "jail_template" di bawah System> Packages sehingga saya bisa membuat penjara FreeBSD untuk mengkompilasi dan menginstal nginx pada sistem pfsense.

  2. Saya mengkonfigurasi penjara untuk server nginx saya di bawah Services> Jails , memberikan penjara baru nama host dan alamat IP yang sama dari alias IP virtual yang saya jalankan HAproxy. Saya mengikat penjara ke antarmuka WAN. Saya menggunakan templat jail default dan mengaktifkan unionfs daripada nullfs.

  3. Begitu penjara sudah dimulai, aku masuk ke kotak pfsense dan berlari jlsmencari nomor penjara. Saya kemudian berlari jexec 1 shuntuk mendapatkan sebuah shell di dalam penjara. Dari sana saya mengatur port BSD dan menginstal nginx menggunakan:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Saya kemudian mengkonfigurasi nginx untuk mendengarkan pada port 443, dan meneruskan semua permintaan ke HAproxy pada port 80, termasuk IP asli dan status SSL di dalam header HTTP. usr/local/etc/nginx/nginx.confPenampilan saya seperti:

    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. Saya kemudian memodifikasi aplikasi PHP saya untuk mendeteksi X-Forwarded-ProtoHTTP Header:

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

Jadi pengaturan terakhir adalah:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]
Josh
sumber
2
Anda harus menonaktifkan SSLv2 kecuali Anda benar-benar membutuhkannya. gnu.org/software/gnutls/manual/html_node/... Saya tidak tahu mengapa Nginx masih mendukungnya dalam konfigurasi default.
Ochoto
Sadari juga bahwa dengan 1024 koneksi pekerja Anda akan mendukung paling banyak 512 klien secara bersamaan.
Ochoto
@Ochoto: Terima kasih untuk kedua tips itu! Saya baru mengenal HAproxy tetapi bahkan kurang terbiasa dengan nignx ...
Josh
7

Konfigurasi saya untuk versi 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

Menggunakan ssl_fcACL. Harap dicatat bahwa option http-server-closebagian ini sangat penting.

greg0ire
sumber
Terima kasih! Saya menjalankan HAProxy v1.4 jadi saya rasa saya tidak bisa melakukan ini, tetapi mungkin membantu orang lain.
Josh
Ya, dan 1,5 harus segera keluar.
greg0ire
5

HAProxy tidak dapat mencapai backend SSL tanpa menggunakan mode TCP mentah, kehilangan X-Forwarded-For, tetapi, Anda berpotensi dapat mengenkripsi ulang lalu lintas dengan stunnel mendengarkan untuk transit backend. Jeleknya.

Saya suka pendekatan Ochoto lebih baik, dengan peringatan: nginx adalah penyeimbang beban yang sangat mampu; jika Anda menggunakannya, saya akan mengatakan menggunakannya untuk semuanya. Proksi HTTPS Anda yang masuk untuk memuat backend HTTPS yang seimbang - dan dengan demikian, tidak perlu header khusus untuk informasi SSL (kecuali Anda memang memerlukan sertifikat klien).

Shane Madden
sumber
Saya tidak yakin mengapa saya berpegang teguh pada HAproxy. Saya pikir itu karena pfSense memiliki paket untuk itu, dan SOIS menggunakannya. Tidak ada satu pun alasan yang bagus. :-)
Josh
Saya ngelantur dari nginx menjadi penyeimbang beban yang mumpuni, kecuali jika Anda menggunakan modul non standar upstream_fair ia melakukan round robin sederhana (atau hash ip klien) tanpa memperhitungkan apakah backend tujuan sudah sibuk dengan permintaan dan dengan demikian meningkatkan antrian di backend saat ada backend lain gratis dan menunggu pekerjaan. HAProxy juga memantau backend dengan baik dan menampilkan statistik tentang mereka.
Ochoto
Jika hanya satu dari yang berikut ini yang menjadi kenyataan a) Nginx mendapat pelacakan keadaan yang layak dan keseimbangan beban yang adil b) HAProxy mendapat dukungan SSL yang layak Satu hanya dapat berharap
Yavor Shahpasov
Saya baru saja menggunakan setup menggunakan nginx -> haproxy -> nginx -> backend untuk SSL, ini disebabkan oleh kurangnya dukungan HTTPS di haproxy seperti yang dibahas di sini, tetapi juga karena nginx tidak mendukung skrip pemeriksaan kesehatan http.
Geoffrey
2

Saya mengimplementasikan solusi tahun lalu untuk mengintegrasikan HAProxy dengan pfSense dengan cara yang memanfaatkan semua fitur HAProxy dan mempertahankan isolasi yang baik dengan pfSense. Sehingga merupakan opsi yang layak untuk lingkungan produksi . SSL diakhiri di HAProxy . Saya menginstal HAProxy di dalam penjara di pfSense menggunakan ezjail dan Ports Collection . Dengan begitu sangat mudah untuk mempertahankan kedua komponen secara mandiri. Dan Anda dapat menginstal versi apa pun yang Anda inginkan. Saya mulai dengan 1,5-dev13. Dan sejak itu bekerja dengan baik untuk saya. Saya telah mendokumentasikan semuanya di sini.

Menginstal HAProxy di pfSense

BTW Willy, terima kasih banyak untuk produk yang luar biasa ini.

Dinesh Sharma
sumber