HAProxy com SNI e diferentes configurações de SSL

9

Eu tenho HAProxy para meus dois sites, um deles público e outro privado.

www.mysite.com private.mysite.com

Atm, estou usando haproxy assim:

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

O que isso deve fazer é solicitar um certificado de cliente (opcionalmente) e continuar. Se o domínio não for www.example.com e o visitante não puder fornecer o certificado correto ou o caminho for / ghost / e o visitante não puder fornecer o certificado correto, deverá ser redirecionado para https://www.example.com

Até agora, isso funciona bem. No entanto, recebi reclamações dos usuários de Mac que navegavam no meu site com o Safari de que continuavam sendo solicitados pelo certificado quando navegavam em https://www.example.com/, enquanto, por exemplo, o Firefox apenas solicita quando navega em https: //private.example .com / ou https://www.example.com/ghost/ .

Aparentemente, é assim que o Safari funciona, então não posso consertar isso. Minha ideia era usar o SNI para dividir entre diferentes frontends

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

Claro que isso não funciona porque

uma. Não posso ter dois frontends escutando na porta 443 com apenas um IP público b. Ainda não encontrei uma maneira de dizer "use_frontend if domain_www" ou algo assim. (Use apenas back-end ou use-server)

Eu também tentei fazê-lo com três servidores 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

Isso funciona, mas o problema aqui é que o haproxy-private solicita o certificado do cliente, mas a solicitação não chega ao navegador. De alguma forma, haproxy-sni descarta o pedido.

Além disso, agora tenho três servidores haproxy que não são desejáveis ​​(embora seja uma opção possível se não encontrar uma solução melhor).

De preferência, eu gostaria de algo assim (inventado .. não sei as opções reais)

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
  ...

Eu espero que alguém possa me ajudar com isso...

mohrphium
fonte

Respostas:

13

Encontrei uma solução para esse problema, que não requer servidores ou serviços adicionais. Não tenho muita certeza se isso não gera novos problemas. Para mim, parece funcionar agora.

A maneira como fiz isso foi criar um frontend para cada domínio que exigisse configurações diferentes de SSL. Em seguida, defino a opção de ligação desses frontends como portas altas (elas não são acessíveis ao público!).

Criei outro frontend escutando na porta: 443 para dividir o tráfego com base no SNI e configurei os servidores back-end para 127.0.0.1:high-port.

Dessa forma, eu criei uma espécie de loop no haproxy

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

Aqui está a parte de configuração.

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

Se alguém tiver alguma opinião sobre isso, ou alguma idéia de por que isso pode ser uma má idéia, entre em contato. Funciona, mas estou me perguntando por que use_frontend não é uma opção. Talvez porque seja algo que não deva ser feito por qualquer motivo.

mohrphium
fonte
Boa ideia. Também não encontrei documentação sobre essa configuração. O desempenho é semelhante a esse loop HAProxy?
JB. Com a Monica.
Sry, não sei qual é o desempenho porque A: não o utilizou por muito tempo (por causa dos filtros IP de origem), B: não possui um site de alto tráfego, onde a otimização de desempenho seria mais interessante ...
mohrphium
Eu apenas coloquei o apache2 na frente do haproxy, o que funciona, mas é meio estúpido, porque um ponto de falha na frente do cluster hapeoxy e (eu acho) gargalo de desempenho (eu acho que o hap é mais rápido que o ap2, não tenho dados reais sobre Isso embora.)
mohrphium
3

as versões recentes do haproxy suportam uma configuração chamada crt-listque permite especificar diferentes configurações de TLS com base no certificado correspondente

você pode usá-lo assim:

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]

mais informações: https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list

observação sobre segurança: sempre corresponda seus nomes de host (sensíveis) ao SNI ssl_fc_sni, não ao nome do host HTTP. Caso contrário, um invasor poderá ignorar sua autenticação de certificado de cliente enviando o TLS SNI de, www.example.orgmas defina o nome do host HTTP como private.example.org!

freaker
fonte
O OP está usando o mesmo certificado para ambos. A questão era mais sobre um ca-filecenário diferente .
gre_gor 19/04