Eu tenho procurado e ninguém parece estar tentando escalar a terminação SSL do jeito que sou e estou curioso para saber porque minha abordagem parece tão incomum.
Aqui está o que eu quero fazer, seguido do porquê:
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
Por que essa configuração maluca de Internet -> HAProxy (tcp mode) -> HAProxy (http mode) -> Tomcat
? Em duas palavras: segurança e escalabilidade
Ao descarregar a terminação SSL para os backends da Web (AD) que executam o HAProxy 1.5 e o Tomcat ouvindo apenas na interface de loopback, posso garantir que todo o tráfego é criptografado do cliente para o servidor, sem possibilidade de detectar nada que não seja local para o backend da web.
Além disso, à medida que a demanda de SSL aumenta, posso simplesmente criar novos servidores de back-end (baratos) atrás do balanceador de carga.
Por fim, elimina a exigência de ter os certificados ativos no LB externo e adiciona segurança adicional ao fazer isso, pois um LB comprometido não terá nenhum pems ou certs nele.
Minha situação parece muito semelhante a esta: por que não há exemplos de balanceadores de carga de software dimensionáveis horizontalmente balanceando SSL? , mas não estou usando sessões baseadas em arquivo e, se possível, gostaria de evitar o balanceamento por IP, já que os clientes podem estar vindo de trás de um NAT. / p>
Eu tentei seguir as instruções HAProxy no documento de configuração para usar a tabela de palitos com o ID de SSL ( link ), mas isso não parece manter minha sessão em um servidor de back-end (recarregando a página de estatísticas A / admin? que mostra os saltos de nome de nó em todos os meus servidores de back-end).
É evidente que o balanceamento de carga round-robin está funcionando, mas as sessões persistentes não são.
Veja um exemplo da minha configuração de 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
Um exemplo da minha configuração de back-end para o webA se parece com:
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
Nesta configuração, uma conexão SSL (ou não-SSL) é roteada através do LB para um dos backends de uma maneira round-robin. No entanto, quando eu recarregar a página (fazer uma nova solicitação), é claro que mudo para outro back-end, independentemente de SSL ou não.
Eu testo isso indo para https://LB/haproxy
, que é a URL da página de estatísticas de back-end com o nome do nó (mostra webA pela primeira vez e webB após um recarregamento, e assim por diante com cada recarregamento subseqüente). Indo para http://LB:8888
mostra as estatísticas do LB e mostra todos os meus backends saudáveis.
O que preciso alterar para que as sessões fiquem em um back-end quando o SSL é encerrado no back-end?
Edit: Pergunta: Por que não saltar em servidores de back-end e armazenar a sessão em um armazenamento central (como o memcached)?
Resposta: Como o aplicativo herdado é extremamente frágil e quebra quando a sessão é transportada pelos servidores. Contanto que o usuário permaneça no mesmo back-end, o aplicativo funcionará conforme o esperado. Isso será alterado eventualmente (reescrito), mas não no curto prazo.