Как я могу получить spring безопасность для работы за балансировщиком нагрузки по нескольким доменам?
Мы перемещаем старое приложение java/ spring в AWS, поэтому оно находится за балансировкой нагрузки приложений AWS. Tomcat работает непосредственно за балансировщиками нагрузки на порту 8080, и мы используем HTTP между балансировщиком нагрузки и tomcat.
Проблема заключается в том, что этот модуль безопасности spring не распознает, что соединение безопасно.
Я могу решить эту проблему, настроив Connection:
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
proxyName="single-host.example.com"
secure="true"
scheme="https"
redirectPort="443"
proxyPort="443" />
Что работает для одного имени хоста. Однако мне нужно это, чтобы работать с несколькими именами хостов.
Я пробовал пропустить прокси и добавил:
server.tomcat.remote_ip_header=X-Forwarded-For
server.tomcat.protocol_header=X-Forwarded-Proto
Но это, похоже, не имеет никакого значения.
Есть ли способ поддерживать несколько имен хостов в этом сценарии?
Ответы
Ответ 1
AWS LoadBalancer отправляет заголовок X-Forwarded-Proto при запросе прокси.
В Tomcat настройте RemoteIpValve, чтобы request.secure и другой переменной запроса, интерпретируемой из этих заголовков.
<Valve className="org.apache.catalina.valves.RemoteIpValve"/>
Вы также должны опустить настройку proxyName
на Connector
conifiguration, так как она должна автоматически поступать с клапана.
Ответ 2
У меня есть процедура решения. Поэтому я дал 2 предложения. Первое - пошаговое графическое представление, чтобы решить вашу проблему. Если нет, перейдите ко второму.
Во второй используется X-Forwarded-Proto
и соответствующая конфигурация для решения проблемы. Надеюсь, это поможет вам.
Предложение # 1:
Облачная среда Amazon с поддержкой поддержки баланса нагрузки довольно проста. Пошаговое руководство приведено здесь: Эластичная балансировка нагрузки (ELB) с веб-приложением Java + Tomcat + Session Stickiness
Предложение # 2:
phillipuniverse дал решение.
Конфигурирование следующего клапана в Tomcat будет правильно выполнять функцию request.isSecure() с заголовком X-Forwarded-Proto:
<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" />
Это можно добавить к Tomcat server.xml
под элементом <Host>
.
И, конечно же, после всего этого существует очень, очень простое решение, которое исправляет эту проблему с самого начала. Все, что действительно должно было произойти, состояло в том, чтобы изменить фильтры прото-каналов:
if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
до
if (invocation.getHttpRequest().isSecure() ||
"https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
Конечная конфигурация здесь должна быть следующей:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" />
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" />
</list>
</property>
</bean>
После этого
Некоторые предпочитают прерывать SSL на балансировщике нагрузки и не использовать веб-сервер Apache. В этом случае вы часто принимаете трафик в LB на 80/443, а затем отправляете трафик на Tomcat на 8080.
Если вы используете сопоставление портов Spring:
<sec:port-mappings>
<sec:port-mapping http="8080" https="443"/>
</sec:port-mappings>
Это не будет работать, поскольку оно не отменяет сопоставление портов в новых канальных процессорах. Вот конфигурация, которая будет работать:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
Ссылка ресурса: HTTPS/SSL/ Spring Безопасность не работает как в балансировщике нагрузки, так и при отсутствии нагрузки балансировочная среда # 424
Ответ 3
Вы должны установить соединение HTTPS на LB, тогда у вас будет надлежащее соединение TLS между LB и tomcat, поэтому spring перестанет плакать. Вам просто нужно предоставить самозаверяющий сертификат LB и настроить ваш модуль безопасности spring с помощью закрытого ключа, который сгенерировал этот самоподписанный сертификат.
(более сложный вариант: правильно настроить прокси-сервер tomcat, чтобы заставить его инкапсулировать поток HTTP LB в потоке HTTPS. Устанавливать все требования TLS в прокси: сертификат, закрытый ключ...)
Ответ 4
Вы пытались поместить адрес LB в качестве имени прокси? Это может повлиять на ваше дело.
Ответ 5
Был ли какой-либо из этих ответов дать решение?
У нас похожая проблема с использованием HAProxy перед 2-мя внутренними серверами Tomcat. В настоящее время веб-приложения используют аутентификацию на основе форм. Альтернативные серверы хотят повторно аутентифицировать запросы; наш SysAdmin рекомендовал использовать Spring Security вместо этого для решения этой проблемы или повторной аутентификации, но мы не уверены, что перемещение уровня аутентификации из tomcat в spring решит проблему или просто переместит проблему!
Любое направление будет с благодарностью.