如何在HAProxy负载平衡后水平缩放SSL终止?

我一直在环顾四周,似乎没有人试图按照我的方式来扩展SSLterminal,我很好奇为什么我的方法似乎很不寻常。

以下是我想要做的以及为什么:

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 ? 用两个字来说:安全性和可扩展性

通过将SSLterminal卸载到运行HAProxy 1.5的Web后端(AD)和仅在回送接口上监听的Tomcat,我可以保证所有stream量都从客户端encryption到服务器,而不会从本地到networking的任何事件嗅探后端。

另外,随着SSL需求的增加,我可以简单地在负载均衡器后面增加新的(便宜的)后端服务器。

最后,它消除了将证书置于面向外部的LB上的需求,并且由于受到攻击的LB将不会有任何Pem或证书,从而增加了额外的安全性。

我的情况似乎与这一个非常相似: 为什么没有水平可伸缩的软件负载平衡器平衡ssl的例子? 但我没有使用基于文件的会话,如果可能的话,我想避免IP平衡,因为客户端可能来自NAT后面。

我试着按照configuration文档中的HAProxy指令来使用带有SSL ID的粘贴表( http://cbonte.github.com/haproxy-dconv/configuration-1.5.html#4-stick%20store-response )这似乎并没有让我的会话保持到一个后端服务器(重新加载显示所有后端服务器上的节点名称反弹的A / admin?stats页面)。

显然,循环负载平衡正在工作,但粘滞会话不是。

这是我的LBconfiguration的一个例子:

 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的后端configuration示例如下所示:

 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 

在此configuration中,SSL(或非SSL)连接以循环方式通过LB路由到其中一个后端。 但是,当我重新加载页面(提出一个新的请求)很明显,我移动到另一个后端,无论SSL或否。

我通过转到https://LB/haproxy来testing它,后者是具有节点名称的后端统计信息页的URL(第一次显示webA,在重新加载后显示webB,以后每次重新加载)。 去http://LB:8888显示http://LB:8888的统计数据,并显示我的后端全部健康。

当SSL在后端终止时,我需要更改哪些会话才能保持一个后端?

编辑:问题:为什么不反弹后端服务器,并将会话存储在中央存储(如memcached)?

答:由于传统应用程序非常脆弱,会话跨服务器传输时会中断。 只要用户停留在相同的后端,应用程序按预期工作。 这将最终改变(重写),但不会在近期内改变。

首先,这给您的networking服务器添加了不必要的复杂性。

其次,在LB上终止SSL连接意味着你可以在客户端使用keepalive进行连接,从而减lessbuild立连接的复杂部分。 资源最有效的使用也是将工作负载分组。 很多人分离静态和dynamic的内容,在LB的SSL意味着两者可以通过相同的连接来自不同的服务器。

第三,SSL通常以不同于您的networking应用所需的速率进行缩放。 我认为缺乏实​​例是由于一个LB对或Round Robin dns对于大多数人来说已经足够了。 在我看来,你可能高估了SSL的工作量。

另外我不确定你的推理安全性。 除了networking服务器已经运行了更多可能的攻击服务之外,如果LB中有任何漏洞,那么你刚才也介绍了它们到你的networking服务器上呢!