Transparent reverse HAProxy в 3-Legs схеме
-
Коллеги,
никто не разбирался с тем, как сделать прозрачный reverse proxy в классической трехногой схеме на HAProxy? Суть проблемы:
1. Есть pfsense на сервере с тремя сетевыми картами - LAN, WAN, DMZ
2. Между LAN и DMZ - роутинг, выход в WAN из DMZ и LAN - с NAT-ом (естественно)
3. В DMZ находится сервер (пусть будет веб-сервер), к которому обращаются как из LAN, так и из Интернета по HTTP, и по SSH из внутренней сети. Требуется, чтобы этот сервер видел реальные адреса тех, кто к нему обращается по HTTP.
4. На pfsense установлен HAProxy, настроен листенер HTTP на внешний адрес, настроен в качестве бэк-сервера веб-сервер в DMZ.
5. На LAN-интерфейсе разрешены обращения к веб-серверу по HTTP и SSH.Все работает. Однако веб-сервер видит пользователей LAN по адресам, а пользователей из Интернета - по адресу HAProxy.
Если теперь в настройках бэк-сервера включить прозрачное проксирование, то веб-сервер начинает видеть пользователей из Интернета правильно, по их адресам, а пользователи из LAN теряют доступ к веб-серверу. Судя по всему, при включении прозрачности генерируется правило ipfw, которое перехватывает весь обратный трафик от веб-сервера, и передает на обработку в HAProxy. А т.к. HAProxy пропускает через себя только трафик из Интернета, то он не знает, что делать с локальным трафиком, и дропит его.
Я так подозреваю, что можно решить проблему настройкой листенера на интерфейсе LAN, но тогда надо будет как-то разносить имена DNS - для HTTP и SSH. Это неудобно. Или настраивать листенеры на LAN и для SSH, и для HTTP (не хотелось бы, т.к. ситуация несколько более сложная, чем описана мною).
Кто-то решал подобную задачу?
P.S. Советы по использованию другого прокси также принимаются
-
http://www.itblah.com/pfsense-backend-web-servers-log-firewalls-ip-access-logs/
http://habrahabr.ru/post/247297/
http://serverfault.com/questions/302282/how-can-i-use-haproxy-with-ssl-and-get-x-forwarded-for-headers-and-tell-php-that
http://www.helptouser.com/server/302282-how-can-i-use-haproxy-with-ssl-and-get-x-forwarded-for-headers-and-tell-php-that.htmlhttp://www.itblah.com/pfsense-enable-stats-latest-devel-package/
P.s. Как вариант :
https://forum.pfsense.org/index.php?topic=79798.0- делаем 1 апач-прокси во внутренней сетке, пробрасываем 80/443 на него. Можно заюзать ngnix в качестве фронтеда.
- настраиваем на нём домены в апаче с редиректами на нужные серые серваки
- раскидываем домены по сервакам.
-
Спасибо за ответ. К сожалению, все эти описания просто о реверсном прокси, и не затрагивают тему собственно его прозрачности. В лучшем случае они подразумевают, что бэк-сервер нормально понимает X-Forwarded-For. В моем случае это не так.
У Апача тоже с прозрачностью проблемы, как и у сквида. Я имею в виду - как минимум в рамках конфигуратора pfSense.
Вот если попробовать продолжить в сторону HAProxy (ну нравится мне он! :) )
Для каждого "прозрачного" бэкенда конфигуратор HAProxy генерирует правило ipfw вида
fwd ::1 tcp from <адрес_бэкенда> <порт_бэкенда> to any in recv <интерфейс_бэкенда>
Вот можно как-то подправить "to any" так, чтобы было "ко всем, кроме серых"? Или "ко всем кто не на LAN-интерфейсе"? Подправить так, чтобы при реконфиге не ломалось?
-
А если убрать из вашей схемы haproxy?
И сделать редирект (port forward) порта на внешнем интерфейсе в DMZ.
А такой же редирект на внутреннем интерфейсе в DMZ.
И для сайтов сделать split dns - во внешний мир отдавать внешний IP. В LAN - внутренний IP.
В итоге с LAN-а на web-сервер пользователи не будут ходить через внешний интерфейс шлюза.
И в логе web-сервера у вас будут настоящие адреса источников запросов (без обработки заголовков x-forward …). -
А если убрать из вашей схемы haproxy?
И сделать редирект (port forward) порта на внешнем интерфейсе в DMZ.Это издержки моего упрощенного описания ситуации :) На самом деле все сложнее - в DMZ куча всяких серверов, висящих на одних и тех же внешних адресах-портах, отличающихся доменными именами. Так что без реверсного прокси не обойтись. Вот какой выбрать и как настроить - вопрос.
squid3 в составе pfSense весь какой-то нехороший, на 80 и 443 порты ругается, требует либо лезть в настройки ядра, либо заворачивать трафик через loopback, никак не делает прозрачность. Вот апач еще не пробовал. У него с прозрачностью как?
-
Так что без реверсного прокси не обойтись.
Ну почему же.
Web-сервер нормально понимает ServerName и по нему направит запрос необходимому сайту.У Apache это параметр "ServerName".
http://httpd.apache.org/docs/2.4/vhosts/name-based.htmlУ nginx - "server_name".
-
Но если все же решите haproxy использовать, то включайте опцию "forwardfor" на фронтэнде.
А на сервере-получателе запроса в DMZ вычитывайте этот заголовок.
У nginx задайте свой формат лога "log_format" и добавьте там, где хотите, параметр "$http_x_forwarded_for".
И будете видеть реальный src IP. -
Ну почему же.
Web-сервер нормально понимает ServerName и по нему направит запрос необходимому сайту.У Apache это параметр "ServerName".
http://httpd.apache.org/docs/2.4/vhosts/name-based.htmlУ nginx - "server_name".
Вообще-то это и есть реверсный прокси. Особенно если "необходимые сайты" живут не на том же самом сервере, который принимает соединение :)
Но если все же решите haproxy использовать, то включайте опцию "forwardfor" на фронтэнде.
А на сервере-получателе запроса в DMZ вычитывайте этот заголовок.
У nginx задайте свой формат лога "log_format" и добавьте там, где хотите, параметр "$http_x_forwarded_for".
И будете видеть реальный src IP.Вопрос не в логах, а в настоящей прозрачности.
-
@IB:
У Apache это параметр "ServerName".
http://httpd.apache.org/docs/2.4/vhosts/name-based.html
У nginx - "server_name".Вообще-то это и есть реверсный прокси. Особенно если "необходимые сайты" живут не на том же самом сервере, который принимает соединение :)
Нет, это обычный "Name-based Virtual Host".
Вопрос не в логах, а в настоящей прозрачности.
Тогда что вы понимаете под "настоящей прозрачности"?
-
Нет, это обычный "Name-based Virtual Host".
Если сайты на том же сервере. Если на других - …
Тогда что вы понимаете под "настоящей прозрачности"?
На целевой сервер TCP-соединение приходит от адреса клиента, а не реверсного прокси.
-
squid3 в составе pfSense весь какой-то нехороший, на 80 и 443 порты ругается, требует либо лезть в настройки ядра, либо заворачивать трафик через loopback, никак не делает прозрачность
Пропишите адреса необходимых Вам ресурсов в исключения (в Destination). Тогда на эти ресурсы будете ходить мимо сквида - напрямую.
-
squid3 в составе pfSense весь какой-то нехороший, на 80 и 443 порты ругается, требует либо лезть в настройки ядра, либо заворачивать трафик через loopback, никак не делает прозрачность
Пропишите адреса необходимых Вам ресурсов в исключения (в Destination). Тогда на эти ресурсы будете ходить мимо сквида - напрямую.
Так у него я все равно прозрачность не нашел, у сквида. Плохо искал?
-
@IB:
На целевой сервер TCP-соединение приходит от адреса клиента, а не реверсного прокси.
Как мне кажется, вы многого хотите :)
И чтобы соединение было прямое, не проксированное, и чтобы хосты назначения были разные …
Тогда только прокси, который по имени будет различать к какому бакэенду направить запрос.
Средствами pf вы не сделаете проброс порта по условию ... Т.е. если имя сайта такое-то - туда иди. Такое - сюда ходи ... :)
Это только (чем я делал) - haproxy или nginx.
И логи смотреть на фронтэнде - здесь будут честные IP источников запроса.
На бакэендах будет IP прокси. Будь то или squid, или haproxy, или nginx, или ...
Выход из ситуации - это обработка заголовка "x-forwarded-for" или "x-real-ip" (какой добавите на фронтэенде) на бакэнде. -
@IB:
HAProxy пропускает через себя только трафик из Интернета, то он не знает, что делать с локальным трафиком, и дропит его.
К какому адресу обращаются клиенты из LAN идущие на веб-сервер? В смысле к локальному или публичному?
-
-
Sorry i dont speak Russian, but do maintain haproxy package on pfSense..
Trying to read / translate this thread im thinking some people are having a slight misunderstanding of the underlying problem presented. If you want to be able to proxy a ssh connection (which i think is one of the desired outcome's?) its not possible to insert a x-forwarded-for header. But haproxy can proxy those connections while keeping the client-ip available to the backend, i think you found that option "Transparent ClientIP" in the backend configuration right?
The desired scenario would be like described here: http://blog.haproxy.com/2011/08/03/layer-7-load-balancing-transparent-proxy-mode/ where the clientip is also used for the connection to the webserver however because pf on freebsd currently does not yet support 'diver-reply' even though it is documented, some trickery is done with ipfw is done to divert reply packets from the webserver back to the haproxy client socket with a non-local ip address.
However this ipfw rule causes trouble for direct clien to webserver traffic .. Im not aware of any other possibility to implement this currently besides waiting for the divert-reply to get implemented into FreeBSD.. ( https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=188511 ) If someone knows a better way im open to suggestions ;) .
For http based traffic inserting the x-forwarded-for header is a good option though..
If i'm totally missing the point, sorry for this non-russian post.
-
Я, честно говоря, не знаю как там haproxy встраивается в поток, но попробуйте обратиться из LAN к публичному адресу веб-сервера и посмотрите, что будет. По идее, запрос должен попасть в прозрачный haproxy и далее по назначению, т. к. слушаюший socket привязывается к IP, а не к интерфейсу. pfSense пофиг к какому из его собственных IP вы обратились - все попадет в local process, т. е. в haproxy.
Если не поможет, можно (если можно) попробовать повесить листенер на loopback и делать port forward на 127.0.0.1 как с WAN, так и с LAN
-
…но попробуйте обратиться из LAN к публичному адресу веб-сервера и посмотрите, что будет. По идее, запрос должен попасть в прозрачный haproxy и далее по назначению, т. к. слушаюший socket привязывается к IP, а не к интерфейсу. pfSense пофиг к какому из его собственных IP вы обратились - все попадет в local process, т. е. в haproxy.
Если не поможет, можно (если можно) попробовать повесить листенер на loopback и делать port forward на 127.0.0.1 как с WAN, так и с LAN
Навскидку обращение из LAN на WAN-адрес не проходит - браузер шлет запрос на внешний адрес, а ответ получает с внутреннего.
Насчет заворота на loopback с листенером на нем - попробую позже, отпишусь. По идее должно сработать. Но гемора с настройками будет…
-
Sorry i dont speak Russian, but do maintain haproxy package on pfSense..
I repeat my question here: https://forum.pfsense.org/index.php?topic=98017.0 Sorry my English ;)
-
Да, с транспарент могут быть проблемы, о чем и предупреждает pfsense:
"WARNING Activating this option will load rules in IPFW and might interfere with CaptivePortal and possibly other services due to the way server return traffic must be 'captured' with a automatically created fwd rule. This also breaks directly accessing the (web)server on the ports configured above. Also a automatic sloppy pf rule is made to allow HAProxy to server traffic."Прочитал ваш вопрос на английском.
"Servers S1 and S2 must see real client IP" - какие там web-сервера используются?
Это я к тому, что haproxy умеет добавлять заголовок "X-Forwarded-For", а Apache и nginx (да и IIS тоже, и другие наверняка) умеют его обрабатывать.
Вот ссылка на документацию nginx - http://nginx.org/ru/docs/http/ngx_http_realip_module.html
"Модуль ngx_http_realip_module позволяет менять адрес клиента на переданный в указанном поле заголовка."
Т.е. и в логе, и в переменной _SERVER["REMOTE_ADDR"] будет адрес источника, а не прокси.https://rtcamp.com/tutorials/nginx/forwarding-visitors-real-ip/