Использование 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, без использования двух разных стеков.
WinXP / IE8 и Java 6 не поддерживают прямую секретность с безопасным протоколом, поэтому тест не наказывает вас за его сбой. Все остальные браузеры будут использовать прямую секретность, если вы принудительно упорядочите сервер. (Если вы этого не сделаете, Win Phones потерпит неудачу.)
Рейтинг A + требует установки Strict-Transport-Security с периодом времени не менее 180 дней.