Назад | Перейти на главную страницу

Могу ли я использовать новую функцию «захвата» HAProxy для сохранения удаленного адреса в интерфейсе TCP и использовать его в качестве заголовка X-Forwarded-For в бэкэнде HTTP?

Использование HAProxy 1.6 и умный хак, Теперь у меня есть интерфейс HAProxy tcp mode, который определяет, поддерживает ли браузер SNI, и на основании этого направляет к сильно зашифрованному бэкэнду завершения SSL или более слабому. Это обеспечивает оценку A + в лабораторных исследованиях SSL, при этом позволяя всем браузерам, кроме IE6, использовать SSL.

Вот мой конфиг. В нем есть несколько шаблонных переменных, которые не требуют пояснений, но не относятся к областям, имеющим отношение к моему вопросу:

frontend https_incoming
 bind 0.0.0.0:443
 mode tcp
 option tcplog
 tcp-request inspect-delay 5s
 tcp-request content accept if { req.ssl_hello_type 1 }
 use_backend https_strong if { req.ssl_sni -m end .transloadit.com }
 default_backend https_weak

backend https_strong
 mode tcp
 option tcplog
 server https_strong 127.0.0.1:1665

frontend https_strong
 bind 127.0.0.1:1665 ssl crt ${DM_ROOT_DIR}/envs/ssl/haproxy-dh2048.pem no-sslv3 no-tls-tickets ciphers ${strongCiphers}
 mode http
 option httplog
 option httpclose
 option forwardfor if-none except 127.0.0.1
 http-response add-header Strict-Transport-Security max-age=31536000
 reqadd X-Forwarded-Proto:\ https
 reqadd FRONT_END_HTTPS:\ on
 use_backend http_incoming

backend https_weak
 mode tcp
 option tcplog
 server https_weak 127.0.0.1:1667

frontend https_weak
 bind 127.0.0.1:1667 ssl crt ${DM_ROOT_DIR}/envs/ssl/haproxy.pem no-sslv3 ciphers ${weakCiphers}
 mode http
 option httplog
 option httpclose
 option forwardfor if-none except 127.0.0.1
 http-response add-header Strict-Transport-Security max-age=31536000
 reqadd X-Forwarded-Proto:\ https
 reqadd FRONT_END_HTTPS:\ on
 use_backend http_incoming

Проблема: https_incoming веб-интерфейс знает IP-адрес клиента, но поскольку он находится в mode tcp, он не может сохранить эту информацию в mode http X-Forwarded-For заголовок. option forwardfor не действует в режиме TCP.

Из еще вопрос по serverfault Я уже обнаружил, что могу использовать:

Таким образом X-Forwarded-For заголовок даже больше не нужен, насколько я понимаю, в случае LVS: пакеты подделываются, поэтому источником становится IP-адрес клиента, а в случае PROXY: пакеты инкапсулируются для переноса IP-адреса клиента.

Кажется, что оба они могут работать. LVS, однако, кажется нам хирургическим вмешательством на сердце, которое может иметь побочные эффекты, а PROXY имеет обратную сторону: прокси-серверы / приложения вверх / вниз по течению могут быть еще не полностью совместимы.

Я действительно надеялся на что-то более легкое, и именно тогда я нашел новый Функция "захвата" в HAProxy 1.6 как упоминается:

вы можете объявить слоты захвата, хранить в них данные и использовать их в любое время в течение сеанса.

далее будет показан следующий пример:

defaults 
 mode http

frontend f_myapp
 bind :9001
 declare capture request len 32 # id=0 to store Host header
 declare capture request len 64 # id=1 to store User-Agent header
 http-request capture req.hdr(Host) id 0
 http-request capture req.hdr(User-Agent) id 1
 default_backend b_myapp

backend b_myapp
 http-response set-header Your-Host %[capture.req.hdr(0)]
 http-response set-header Your-User-Agent %[capture.req.hdr(1)]
 server s1 10.0.0.3:4444 check

Мне кажется, информация хранится во внешнем интерфейсе, а затем используется в серверной части, поэтому, возможно, я могу взять клиентский IP-адрес в режиме TCP, сохранить его и использовать его позже, может быть, так:

http-response set-header X-Forwarded-For %[capture.req.hdr(0)]

Я посмотрел на захватить документы и там кажется, что захват больше ориентирован на заголовки режима http, но потом я также видел разговор по списку рассылки успешно демонстрируя использование tcp-request capture.

Я пробовал несколько вещей, среди которых:

tcp-request capture req.hdr(RemoteAddr) id 0
# or
tcp-request content capture req.hdr(RemoteHost) id 0

Но, как видите, я понятия не имею, каким должен быть синтаксис и под каким ключом эта информация будет доступна, и я не могу найти ее в (я думаю) соответствующая документация.

Вопросы: Можно ли захватить IP-адрес клиента в режиме TCP, а затем записать эту информацию в X-Forwarded-For заголовок в режиме HTTP? Если да, то каков будет синтаксис для этого?

Отвечая на мой собственный вопрос, это не представляется возможным, поскольку здесь трафик «покидает» HAProxy:

       TCP                             HTTP
frontend->backend (->leaving->) frontend->backend

Таким образом, контекст теряется, и захват не может быть сохранен. Вместо этого, как "PiBa-NL" вчера предложил в IRC на #haproxy на Freenode:

[5:29pm] PiBa-NL: kvz, use proxy-protocol between back and front
[5:54pm] kvz: PiBa-NL: Thanks, does this mean my app also needs to understand 
         the proxy protocol, or will it be 'stripped' once it reaches the 
         backend. I don't think my node.js server could handle it without  
         significant changes to its stack
[6:07pm] kvz: Or let me rephrase: could I enable the proxy protocol on the first 
         frontend, then 'unwrap' it in the second frontend, taking the client ip 
         and putting it into the http header - so that my app would not have to 
         be proxy protocol compatible, and it would just be means to carry the 
         client ip from first frontend to the second?
[6:49pm] PiBa-NL: kvz, the last part you can still use the x-forwarded-for header
[6:50pm] PiBa-NL: but between haproxy backend and frontend you would use the 
         proxyprotocol to make the second frontent 'know' the original client ip
[6:50pm] PiBa-NL: server https_strong 127.0.0.1:1665 send-proxy
[6:50pm] PiBa-NL: bind 127.0.0.1:1665 ssl crt .... accept-proxy
[6:52pm] PiBa-NL: the second frontend can then still use the  
         'option forwardfor', and it should insert the wanted header
[6:53pm] PiBa-NL: so basically 'yes' 

Это означает, что протокол PROXY используется только для склеивания двух интерфейсов вместе, инкапсулируя Cient IP, но второй интерфейс разворачивает его и сохраняет в X-Forwarded-For заголовок через option forwardfor, так что его бэкэнд может отправлять на мой сервер приложений запрос без протокола PROXY, а это означает, что мне не нужно беспокоиться о проблемах совместимости в восходящем / нижнем направлении.

HAProxy уже должен добавлять заголовок X-Forwarded-For. Вы можете добавить протокол и / или порт, если какой-либо из них нестандартный.

Я обычно тестирую такое поведение на странице, которая повторяет заголовки запроса. Это позволяет легко увидеть, какие заголовки доступны и каково их содержимое.

В X-Forward-For нет ничего необычного в том, чтобы содержать список адресов. Это сигнализирует о том, что запрос прошел через несколько прокси-серверов или кто-то подделывает заголовок. Самый правый адрес будет тем, который был добавлен последним прокси-сервером (ha-proxy), обработавшим запрос.

Некоторые веб-серверы можно настроить для регистрации IP-адреса из заголовка, а не из соединения. Это было бы полезно для ваших журналов доступа и случая, когда вы хотите сгенерировать заголовок на основе IP-адреса входящих подключений.

Можно получить рейтинг A + при поддержке всех перечисленных браузеров, кроме IE 6, без использования двух разных стеков.

  • Для Java 6 отключите хотя бы DHE-RSA-AES128-SHA и AES128-SHA. Возможно, это все шифры без прямой секретности.
  • Для WinXP / IE8 и Java6 включите DES-CBC3-SHA и / или EDH-DSS-DES-CBC3-SHA. Это должны быть наименее предпочтительные шифры, поскольку они не поддерживают прямую секретность.

WinXP / IE8 и Java 6 не поддерживают прямую секретность с безопасным протоколом, поэтому тест не наказывает вас за его сбой. Все остальные браузеры будут использовать прямую секретность, если вы принудительно упорядочите сервер. (Если вы этого не сделаете, Win Phones потерпит неудачу.)

Рейтинг A + требует установки Strict-Transport-Security с периодом времени не менее 180 дней.