具有SNI和不同SSL设置的HAProxy


9

我的两个站点都有HAProxy,其中一个是公共站点,另一个是私有站点。

www.mysite.com private.mysite.com

自动取款机,我正在像这样使用haproxy:

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3
  mode http
  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/
  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert

  use_backend bknd_private if domain_private
  use_backend bknd_www     if domain_www

  default_backend bknd_www

这应该做的是索取客户端证书(可选)并继续。如果域不是www.example.com,并且访问者不能提供正确的证书,或者路径是/ ghost /,并且访问者不能提供正确的证书,则应将其重定向到https://www.example.com。

到目前为止,一切正常。但是,我收到Mac用户使用Safari浏览我的网站的投诉,他们在https://www.example.com/上浏览时不断询问他们的证书,而例如Firefox仅在浏览https://private.example时询问。.com /https://www.example.com/ghost/

显然,这就是Safari的工作方式,因此我无法解决。我的想法是使用SNI在不同的前端之间进行划分

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3

frontend private_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3

当然那是行不通的,因为

一个。我不能有两个前端仅使用一个公共IP b侦听端口443。我还没有找到说“ use_frontend if domain_www”之类的方法。(仅use_backend或use-server)

我也尝试过使用三个haproxy服务器来做

frontend haproxy-sni
bind *:443 ssl crt /etc/mycert.pem no-sslv3
mode tcp

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }

acl domain_www ssl_fc_sni_end -i www.example.com

use-server server1 haproxy-private.lan  if !domain_www
use-server server2 haproxy-public.lan   if domain_www

这行得通,但是这里的问题是haproxy-private要求提供客户端证书,但请求没有到达浏览器。haproxy-sni以某种方式放弃了该请求。

另外,我现在有三台haproxy服务器,这是不理想的(尽管如果找不到更好的解决方案,这是一个可能的选择)。

最好我想要这样的东西(组成..不知道真正的选择)

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3
  mode http

  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/

  ssl_options ca-file /etc/myca.pem verify optional if !www_domain          # made up!
  ssl_options ca-file /etc/myca.pem verify optional if !path_ghost          # made up!

  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert
  ...

我希望有人可以帮助我...

Answers:


13

我找到了此问题的解决方案,不需要其他服务器或服务。我不确定这是否不会产生新的问题。对我来说,它现在似乎可以正常工作。

我这样做的方法是为需要不同ssl设置的每个域创建一个前端。然后,我将这些前端的bind选项设置为高端口(这些端口无法从公共端口访问!)。

我创建了另一个监听端口:443的前端,以基于SNI划分流量,并将后端服务器设置为127.0.0.1:high-port。

这样,我在haproxy中创建了一个循环

[incoming]->[haproxy:443]->[haproxy:7000]->[www.intern.lan]
[incoming]->[haproxy:443]->[haproxy:8000]->[private.intern.lan]

这是配置部分。

frontend frnd_snipt                                             # Frontend_SNI-PassThrough (snipt)
  bind *:443                                                    # Do not use bind *:8443 ssl crt etc....!
  option tcplog
  mode tcp 

  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 } 

  acl subdomain_is_www   req_ssl_sni -i www.example.com
  acl subdomain_is_www   req_ssl_sni -i example.com
  acl subdomain_is_private req_ssl_sni -i private.example.com

  use_backend bknd_snipt_private if subdomain_is_private
  use_backend bknd_snipt_www  if subdomain_is_www

backend bknd_snipt_www
  mode tcp                                              # tcp mode must match the frontend mode - already set as default in [global]
  server snipt-www 127.0.0.1:7000                       # run without "check", otherwise haproxy checks itself all the time!

backend bknd_snipt_private
  mode tcp     
  server snipt-private 127.0.0.1:8000                   # also, don't add "ssl" when in tcp mode. "ssl" is an http mode option (result in "NO-SRV" when set in tcp)

##### NORMAL HAPROXY PART #####
frontend www_example_com                                # this frontend can be in tcp or http mode...
  bind *:7000 ssl crt /etc/mycert.pem no-sslv3          # www. frontend with normal https
  mode http
  option httplog


frontend private_example_com
  bind *:8000 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3        # private. frontend with client certificate request.
  mode http
  option httplog
  ... # whatever you have in your frontend

如果有人对此有任何想法,或有任何想法为什么这可能不是一个好主意,请告诉我。它可以工作,但是我想知道为什么use_frontend不是一个选项。也许是因为无论出于什么原因都不应该这样做。


好主意。我也找不到有关此设置的文档。该HAProxy循环的性能是否相似?
JB。和莫妮卡。

对不起,我不知道它的性能如何,因为A:长期未使用(由于源IP过滤器),B:没有高流量的站点,在该站点上,性能优化会更加有趣...
mohrphium

我只是将apache2放在haproxy的前面,它可以工作,但是有点愚蠢,因为在hapeoxy集群前面的单点故障和(我认为)性能瓶颈(我认为hap比ap2快,没有关于真实数据的信息)。那)
。– mohrphium

3

最新版本的haproxy支持一个名为的设置crt-list,该设置使您可以根据匹配的证书指定不同的TLS设置

您可以像这样使用它:

haproxy.conf:

frontend https
    mode http
    bind *:443 ssl crt-list /etc/haproxy/crt-list.conf ca-file ca.pem

    use_backend test if { ssl_fc_sni -i test.area.example.org }
    use_backend private if { ssl_fc_sni -i private.example.org }
    default_backend www

crt-list.conf:

www.pem [verify none]
www.pem [verify required] *.area.example.org
private.pem [verify required]

更多信息:https : //cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list

安全注意事项:始终将您的(敏感)主机名与SNI ssl_fc_sni而不是HTTP主机名进行匹配。否则,攻击者可能会通过发送TLS SNI,www.example.org但将HTTP主机名设置为private.example.org!来绕过您的客户端证书身份验证。


OP为两者使用相同的证书。问题更多是关于不同的ca-file设置。
gre_gor
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.