Подтвердить что ты не робот

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-адреса, отправляемые обратно клиентам, при переходе через прокси-сервер?

4b9b3361

Ответ 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") об уважении адреса пересылки прокси.