Spring Boot со встроенным Tomcat за прокси-сервером Apache
У нас есть приложение Spring Boot (Spring MVC) со встроенным Tomcat на выделенном сервере приложений за прокси-сервером Apache SSL.
Порт SSL на прокси-сервере - 4433, переадресация на порт 8080 на сервере приложений.
Таким образом, URL-адрес прокси-сервера пересылается так:
https://proxyserver:4433/appname >>forward>> http://appserver:8080/
При запуске БЕЗ прокси, первое, что происходит, это то, что
Spring Security перенаправляет запрос, например:
http://appserver:8080/ >>redirect>> http://appserver:8080/login
отобразить форму входа, расширив WebSecurityConfigurerAdapter
...
httpSecurity.formLogin().loginPage("/login") ...
...
Без прокси работает нормально, но С прокси редирект нужно менять,
поэтому Spring вместо этого должен перенаправить на соответствующий прокси-URL, например:
http://appserver:8080/ >>redirect>> https://proxyserver:4433/appname/login
но успеха пока нет.
Я пытаюсь применить это решение: 59.8. Использовать Tomcat за внешним прокси-сервером.
Мы настроили mod_proxy в Apache и убедились, что он отправляет ожидаемые заголовки:
X-Forwarded-For: xxx.xxx.xxx.xxx
X-Forwarded-Host: proxyserver
X-Forwarded-Port: 4433
X-Forwarded-Proto: https
Приложение запускается с параметрами:
export ARG1='-Dserver.tomcat.protocol-header=x-forwarded-proto'
export ARG2='-Dserver.tomcat.remote-ip-header=x-forwarded-for'
java $ARG1 $ARG2 -jar webapp.jar
Тем не менее редирект не работает.
Он будет продолжать перенаправлять локально на http://appserver:8080/login
который недоступен для клиентов.
Что еще нужно сделать, чтобы этот сценарий работал?
ОБНОВИТЬ
Также меня беспокоит часть "/appname" в URL прокси. На сервере приложений приложение имеет корень "/". Как Spring должен быть проинструктирован о том, что "/appname" должно быть включено во все URL-адреса, отправляемые обратно клиентам, при переходе через прокси-сервер?
Ответы
Ответ 1
У меня была такая же проблема на днях. После некоторой отладки Spring Boot 1.3 я нашел следующее решение.
1. Вы должны настроить заголовки на вашем прокси-сервере Apache:
<VirtualHost *:443>
ServerName www.myapp.org
ProxyPass / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443
ProxyPreserveHost On
... (SSL directives omitted for readability)
</VirtualHost>
2. Вы должны указать приложению Spring Boot использовать эти заголовки. Поэтому поместите следующую строку в ваш application.properties (или в любое другое место, где Spring Boots понимает свойства):
server.use-forward-headers=true
Если вы сделаете эти две вещи правильно, каждая переадресация, которую отправляет ваше приложение, будет идти не по адресу http://127.0.0.1:8080/[path], а автоматически по адресу https://www.myapp.com/[path]
Обновление 1. Документация по этой теме находится здесь. Вы должны прочитать его хотя бы для того, чтобы знать свойство server.tomcat.internal-proxies
которое определяет диапазон IP-адресов для прокси-серверов, которым можно доверять.
Ответ 2
Прокси-сервер выглядит хорошо, и так же работает бэкэнд-приложение, но похоже, что он не видит измененный запрос RemoteIpValve
. Поведение RemoteIpValve
по умолчанию включает совпадение шаблона для IP-адреса прокси (как проверку безопасности), и оно только изменяет запросы, которые, по его мнению, относятся к действительным прокси. Шаблон по умолчанию используется в Spring Boot для известного набора внутренних IP-адресов, таких как 10.*.*.*
и 192.168.*.*
, поэтому, если ваш прокси-сервер не находится на одном из них, вам необходимо явно его настроить, например
server.tomcat.internal-proxies=172\\.17\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}
(используя формат файла свойств, что означает, что вам нужно удвоить escape-обратную косую черту).
Вы можете видеть, что происходит в RemoteIpValve
, если вы установили
logging.level.org.apache.catalina.valves.RemoteIpValve=DEBUG
или установите в нем точку останова.
Ответ 3
Типичное решение этой проблемы - позволить обработчику прокси-сервера любой требуемой перезаписи. Например, в Apache вы можете использовать rewrite_module и/или headers_module исправить заголовки. В качестве другого примера Nginx автоматически обрабатывает этот и другие подобные случаи после настройки серверов восходящего потока.
В ответ на комментарии:
Каковы значения конфигурации загрузки remote_ip_header и протокола_header spring?
Напоминаем spring Boot на мгновение. Tomcat, встроенный контейнер сервлетов, имеет клапан, известный как RemoteIpValve. Этот клапан представляет собой порт Apache remotip_module. Основной целью этого клапана является обращение к "пользовательскому агенту, который инициировал запрос в качестве исходного пользовательского агента" для "целей авторизации и ведения журнала". Чтобы этот клапан использовался, его необходимо настроить.
Более подробную информацию об этом клапане здесь.
Spring Загрузка удобно поддерживает настройку этого клапана через application.properties через свойства server.tomcat.remote_ip_header и server.tomcat.protocol_header.
Ответ 4
У меня был точно такой же случай с использованием haproxy в качестве балансировки нагрузки с приведенной ниже конфигурацией, которая меня беспокоила. Единственное, что IP-адрес клиента находится в request.getRemoteAddr()
, а не в заголовке "X-Forwarded-For"
frontend www
bind *:80
bind *:443 ssl crt crt_path
redirect scheme https if !{ ssl_fc }
mode http
default_backend servers
backend servers
mode http
balance roundrobin
option forwardfor
server S1 host1:port1 check
server S2 host2:port2 check
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
В application.properties:
server.use-forward-headers=true
Ответ 5
Пробовали ли вы настройку
server.context-path=/appname
В Spring Загрузка?
Ответ 6
Попробуйте установить правило перезаписи, например: https://proxyserver: 4433/appname >> forward >> http://appserver: 8080/appname
А затем установите контекст приложения в "appname" server.context-path =/appname
Таким образом, локально вы можете запустить по адресу http://appserver: 8080/appname и через обратный прокси- сервер вы получите доступ через https://proxyserver: 4433/appname
Поскольку я использую JBOSS, изменения в standalone.xm в jboss:
<http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="true" enable-http2="true"/>
Tomcat будет иметь аналогичную конфигурацию, чтобы сообщать Tomcat (proxy-address-forwarding = "true") об уважении адреса пересылки прокси.