Как я могу использовать HAproxy с SSL и получить заголовки X-Forwarded-For И сказать PHP, что SSL используется?

20

У меня есть следующие настройки:

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

Для HTTP-запросов это прекрасно работает , запросы распределяются на мои серверы Apache просто отлично. Для запросов SSL у меня было HAproxy, распределяющее запросы с использованием балансировки нагрузки TCP, и это работало, однако, поскольку HAproxy не действовал как прокси, он не добавлял X-Forwarded-Forзаголовок HTTP, и серверы Apache / PHP не знали клиента реальный IP-адрес.

Итак, я добавил stunnelперед HAproxy, читая, что stunnel может добавить X-Forwarded-Forзаголовок HTTP. Однако пакет, который я мог бы установить в pfSense, не добавляет этот заголовок ... также, это, очевидно, убивает мою способность использовать запросы KeepAlive , которые я действительно хотел бы сохранить. Но самой большой проблемой, которая убила эту идею, было то, что stunnel преобразовал HTTPS-запросы в простые HTTP-запросы, поэтому PHP не знал, что SSL был включен, и пытался перенаправить на сайт SSL.

Как я могу использовать HAproxy для балансировки нагрузки между несколькими серверами SSL, позволяя этим серверам знать IP-адрес клиента и знать, что SSL используется? И если возможно, как я могу сделать это на моем сервере pfSense?

Или я должен отказаться от всего этого и просто использовать nginx?

мистифицировать
источник
3
Re: Stunnel и X-Forwarded-For, смотрите здесь .
Шейн Мэдден
@Shane: спасибо. Именно там я прочитал, что теряю KeepAlive :-)
Джош
2
+1 за отличную диаграмму ASCII. :-)
KyleFarris
@AlanHamlett, ваша ссылка 404.
luckydonald
@luckydonald спасибо, вот обновленная ссылка. Вы можете использовать протокол Proxy, добавив ключевое слово send-proxy в конфигурацию haproxy. Я написал сообщение в блоге с примерами здесь: wakatime.com/blog/23-how-to-scale-ssl-with-haproxy-and-nginx
Алан Хамлетт

Ответы:

17

Вам не нужно отбрасывать все это, вы можете просто использовать nginx перед haproxy для поддержки SSL, сохраняя все свои настройки балансировки нагрузки. Вам даже не нужно использовать nginx для HTTP, если вы не хотите. Nginx может передавать как X-Forwarded-For, так и пользовательский заголовок, указывающий, что SSL используется (и информацию о сертификате клиента, если хотите). Фрагмент конфигурации Nginx, который отправляет необходимую информацию:

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
источник
37

Просто для записи, так как этот поток часто упоминается относительно HAProxy + SSL, HAProxy поддерживает собственный SSL с обеих сторон, начиная с 1.5-dev12. Таким образом, имея X-Forwarded-For, HTTP keep-alive, а также заголовок, сообщающий серверу о том, что соединение было установлено через SSL, так просто:

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

Я уверен, что к тому времени, когда вы придумали что-то другое, но, по крайней мере, новые посетители получат простое решение сейчас :-)

Вилли Тарро
источник
Спасибо, это хорошая общая информация ... мой вопрос был о HAproxy, работающем на pfSense, так что на данный момент мне все еще нужно использовать nginx перед HAproxy, так как pfSense не поддерживает эту версию HAProxy (пока)
Josh
Извините, Джош, я недостаточно знаю о pfSense, чтобы знать, можете ли вы обновить компоненты на нем или нет, и, поскольку вы говорили об установке пакета, я полагал, что это так. В прошлый раз я попробовал это около 5 лет назад, поэтому я не помню всех деталей.
Вилли Тарро
1
Я пока не очень разбираюсь в конфигурации haproxy, но в последней версии мне пришлось добавить acl: acl is-ssl dst_port 443и переписать строку: reqadd X-Forwarded-Proto:\ https if is-sslNginx, похоже, справляется с этим заголовком довольно хорошо
greg0ire
Это работает как шарм. Не требуется nginx.
Джей Тейлор
1
@ greg0ire, потому что в последнем haproxy нет is_ssl, а вместо этого
ssl_fc
12

Для всех, кто найдет этот вопрос, я последовал совету Ochoto и использовал nginx. Вот конкретные шаги, которые я использовал, чтобы заставить это работать на моем маршрутизаторе pfSense :

  1. Используя веб-интерфейс pfsense, я установил пакет pfsense PfJailctl и пакет "jail_template" в разделе System> Packages, чтобы я мог создать джейл FreeBSD для компиляции и установки nginx в системе pfsense.

  2. Я настроил тюрьму для своего сервера nginx в разделе « Службы»> «Тюрьмы» , предоставив новой тюрьме то же имя хоста и IP-адрес виртуального IP-псевдонима, на котором у меня работал HAproxy. Я привязал тюрьму к интерфейсу WAN. Я использовал шаблон тюрьмы по умолчанию и включил unionfs, а не nullfs.

  3. После того, как тюрьма была запущена, я SSHed в поле pfsense и побежал, jlsчтобы найти номер тюрьмы. Затем я побежал jexec 1 shза раковиной в тюрьму. Оттуда я настроил порты BSD и установил nginx, используя:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. Затем я настроил nginx для прослушивания порта 443 и передачи всех запросов HAproxy через порт 80, включая реальный IP-адрес и состояние SSL в заголовках HTTP. Моя usr/local/etc/nginx/nginx.confвыглядит так:

    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. Затем я изменил свое приложение PHP для обнаружения X-Forwarded-Protoзаголовка HTTP:

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

Итак, окончательная настройка:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of apache servers)
                [    (pfSense server)  ]
мистифицировать
источник
2
Вы должны отключить SSLv2, если он вам действительно не нужен. gnu.org/software/gnutls/manual/html_node/… Я не знаю, почему Nginx все еще поддерживает его в конфигурации по умолчанию.
Ochoto
Также поймите, что с 1024 рабочими соединениями вы будете поддерживать не более 512 одновременно работающих клиентов.
Ochoto
@Ochoto: Спасибо за оба этих совета! Я новичок в HAproxy, но еще менее знаком с nignx ...
Джош
7

Моя конфигурация для 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

Он использует ssl_fcACL. Обратите внимание, что эта option http-server-closeчасть очень важна.

greg0ire
источник
Благодарность! Я использую HAProxy v1.4, поэтому не думаю, что смогу это сделать, но это может помочь другим.
Джош
Да и 1.5 должен скоро выйти.
greg0ire
5

HAProxy не может X-Forwarded-Forполучить доступ к бэкэнду SSL без использования режима «сырой» TCP, что приводит к потере , но вы можете потенциально повторно зашифровать трафик с помощью прослушивающего stunnel для транзита бэкэнда. Хотя уродливо.

Мне больше нравится подход Ochoto, с оговоркой: nginx - это идеально способный балансировщик нагрузки; если вы используете это, я бы сказал, использовать его для всего. Проксируйте ваш входящий HTTPS для загрузки сбалансированных бэкэндов HTTPS - и таким образом, нет необходимости в пользовательских заголовках для информации SSL (если вам не нужен сертификат клиента).

Шейн Мэдден
источник
Я не уверен, почему я цепляюсь за HAproxy. Я думаю, это потому, что у pfSense есть пакет для него, и SOIS использует его. Ни один из них не является веской причиной. :-)
Джош
Я отклоняюсь от того, что nginx является способным балансировщиком нагрузки, если только вы не используете нестандартный модуль upstream_fair, он выполняет простой циклический перебор (или хэш ip клиента) без учета того, что бэкэнд-приемник уже занят запросами и, таким образом, растёт очередь в этом бэкэнде, когда Есть и другие свободные бэкэнды, которые ждут работы. HAProxy также хорошо контролирует бэкэнды и отображает статистику о них.
Ochoto
Если только одно из следующего станет правдой а) Nginx получит приличное отслеживание состояния и справедливую балансировку нагрузки б) HAProxy получит приличную поддержку SSL Можно только надеяться
Явор Шахпасов
Я только что развернул установку, используя nginx -> haproxy -> nginx -> backend для SSL, это связано с отсутствием поддержки HTTPS в haproxy, как описано здесь, а также с тем, что nginx не поддерживает сценарии проверки работоспособности http.
Джеффри
2

В прошлом году я реализовал решение для интеграции HAProxy с pfSense таким образом, чтобы он использовал все функции HAProxy и поддерживал хорошую изоляцию с pfSense. Так что это жизнеспособный вариант для производственных сред . SSL прекращается на HAProxy . Я установил HAProxy внутри тюрьмы в pfSense, используя ezjail и Ports Collection . Таким образом, очень легко поддерживать оба компонента независимо друг от друга. И вы можете установить любую версию, какую захотите. Я начал с 1.5-dev13. И с тех пор это работает отлично для меня. Я задокументировал все это здесь.

Установка HAProxy на pfSense

Кстати, Вилли, большое спасибо за такой отличный продукт.

Динеш Шарма
источник