Я смотрел вокруг, и, похоже, никто не пытается масштабировать завершение SSL, как я, и мне любопытно, почему мой подход кажется таким необычным.
Вот что я хочу сделать и поясню почему:
10.0.1.1 10.0.1.2 - 10.0.1.5
-----+--------+----+----+----+
| | | | |
+--+--+ +-+-++-+-++-+-++-+-+
| LB1 | | A || B || C || D |
+-----+ +---++---++---++---+
haproxy 1.5 haproxy 1.5 + tomcat
tcp mode http mode
Почему эта сумасшедшая установка Internet -> HAProxy (tcp mode) -> HAProxy (http mode) -> Tomcat
? В двух словах: безопасность и масштабируемость
Разгрузив завершение SSL на веб-серверы (AD), которые запускают HAProxy 1.5 и Tomcat, прослушивающие только интерфейс обратной петли, я могу гарантировать, что весь трафик будет зашифрован от клиента к серверу без возможности прослушивания чего-либо, не локального в Интернете. бэкэнд.
Кроме того, по мере роста спроса на SSL я могу просто запускать новые (дешевые) серверы позади балансировщика нагрузки.
Наконец, он устраняет требование наличия сертификатов на внешнем LB и добавляет дополнительную безопасность, делая это, поскольку скомпрометированный LB не будет иметь на нем никаких pems или сертификатов.
Моя ситуация кажется очень похожей на эту: почему нет примеров горизонтально масштабируемых программных балансировщиков нагрузки, балансирующих ssl? но я не использую сеансы на основе файлов и, если возможно, я бы хотел избежать балансировки по IP, поскольку клиенты могут приходить из-за NAT.
Я пробовал следовать инструкциям HAProxy в документе конфигурации для использования таблицы стик с идентификатором SSL (http://cbonte.github.com/haproxy-dconv/configuration-1.5.html#4-stick%20store-response), но это не похоже на то, чтобы сохранить мой сеанс на одном внутреннем сервере (перезагрузка страницы статистики A / admin?, которая показывает, что имя узла перескакивает через все мои внутренние серверы).
Очевидно, что циклическая балансировка нагрузки работает, а липкие сеансы - нет.
Вот пример моей конфигурации LB:
global
log 127.0.0.1 local0 notice
maxconn 200
daemon
user appserver
group appserver
stats socket /tmp/haproxy
defaults
log global
mode tcp
timeout client 5000ms
timeout connect 50000ms
timeout server 50000ms
option contstats
frontend frontend_http
log global
bind *:80
default_backend backend_http_servers
frontend frontend_ssl
log global
bind *:443
default_backend backend_servers
listen stats :8888
mode http
stats enable
stats hide-version
stats uri /
#################################################################################################
## NOTE: Anything below this section header will be generated by the bootstrapr process and may be
## re-generated at any time losing manual changes
#################################################################################################
## BACKENDS
#################################################################################################
backend backend_http_servers
mode tcp
#option httpchk
server webA:8081 webA:8081 check port 8081
server webB:8081 webB:8081 check port 8081
# This configuration is for HTTPS affinity from frontdoor to backend
# Learn SSL session ID from both request and response and create affinity
backend backend_servers
mode tcp
balance roundrobin
option ssl-hello-chk
#option httpchk
# maximum SSL session ID length is 32 bytes
stick-table type binary len 32 size 30k expire 30m
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
# use tcp content accepts to detects ssl client and server hello
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# no timeout on response inspect delay by default
tcp-response content accept if serverhello
# SSL session ID (SSLID) may be present on a client or server hello
# Its length is coded on 1 byte at offset 43 and its value starts
# at offset 44
# Match and learn on request if client hello
stick on payload_lv(43,1) if clienthello
# Learn on response if server hello
stick store-response payload_lv(43,1) if serverhello
############################################
# HTTPS BACKENDS
############################################
server webA:8443 webA:8443 check port 8443
server webB:8443 webB:8443 check port 8443
Пример моей конфигурации бэкэнда для webA выглядит так:
global
log 127.0.0.1 local0 info
maxconn 200
daemon
defaults
log global
mode http
option dontlognull
option forwardfor
option httplog
option httpchk # checks server using HTTP OPTIONS on / and marks down if not 2xx/3xx status
retries 3
option redispatch
maxconn 200
timeout client 5000
timeout connect 50000
timeout server 50000
frontend frontend_http
log global
# only allow connections if the backend server is alive
monitor fail if { nbsrv(backend_application) eq 0 }
reqadd X-Forwarded-Proto:\ http # necessary for tomcat RemoteIPValve to report the correct client IP and port
reqadd X-Forwarded-Protocol:\ http # necessary because who knows what's actually correct?
reqadd X-Forwarded-Port:\ 80 # also here for safety
bind *:8081
default_backend backend_application
frontend frontend_ssl
log global
# only allow connections if the backend server is alive
monitor fail if { nbsrv(backend_application) eq 0 }
reqadd X-Forwarded-Proto:\ https # necessary for tomcat RemoteIPValve to report the correct client IP and port
reqadd X-Forwarded-Protocol:\ https # necessary because who knows what's actually correct?
reqadd X-Forwarded-Port:\ 443 # also here for safety
reqadd X-Forwarded-SSL:\ on # also here for safety
bind *:8443 ssl crt /path/to/default.pem crt /path/to/additional/certs crt /path/to/common/certs
default_backend backend_application
#################################################################################################
# Backends
#################################################################################################
backend backend_haproxy
stats enable
stats show-node
stats uri /haproxy
acl acl_haproxy url_beg /haproxy
redirect location /haproxy if !acl_haproxy
backend backend_application
stats enable
stats show-node
stats uri /haproxy
option httpclose
option forwardfor
acl acl_haproxy url_beg /haproxy
server 127.0.0.1:8080 127.0.0.1:8080 check port 8080
В этой конфигурации соединение SSL (или не SSL) маршрутизируется через LB к одному из бэкэндов в циклическом режиме. Однако, когда я перезагружаю страницу (делаю новый запрос), становится ясно, что я перехожу на другой бэкэнд независимо от SSL или нет.
Я проверяю это, перейдя в https://LB/haproxy
который является URL-адресом страницы статистики серверной части с именем узла (показывает webA в первый раз, webB после перезагрузки и так далее при каждой последующей перезагрузке). Собирается http://LB:8888
показывает статистику для LB и показывает, что мои бэкенды все исправны.
Что мне нужно изменить, чтобы сеансы придерживались одного бэкэнда, когда SSL прерывается на бэкэнде?
Изменить: вопрос: почему бы не перебросить бэкэнд-серверы и не сохранить сеанс в центральном хранилище (например, memcached)?
Ответ: Потому что устаревшее приложение очень хрупкое и ломается, когда сеанс переносится между серверами. Пока пользователь остается на одном сервере, приложение работает должным образом. Со временем это будет изменено (переписано), но не в ближайшем будущем.
Во-первых, это добавляет ненужной сложности вашим веб-серверам.
Во-вторых, завершение SSL-соединения на LB означает, что вы можете использовать keepalive на стороне клиента для соединения, уменьшая сложную часть установления соединения. Также наиболее эффективное использование ресурсов - это группировка рабочих нагрузок. Многие люди разделяют статический и динамический контент, SSL в LB означает, что оба могут поступать с разных серверов через одно и то же соединение.
В-третьих, SSL обычно масштабируется с другой скоростью, чем требует ваше веб-приложение. Я думаю, что отсутствие примеров связано с тем, что большинству людей достаточно одной пары LB или Round robin dns. Мне кажется, что вы переоцениваете нагрузку на SSL.
Также я не уверен в ваших рассуждениях относительно безопасности. В дополнение к тому факту, что на веб-сервере уже запущено гораздо больше сервисов с возможными эксплойтами, если в LB есть какие-либо уязвимости, то вы также только что добавили их на свои веб-серверы!