HAProxy com SNI e diferentes configurações de SSL

7

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

www.mysite.com private.mysite.com

Atm, estou usando o 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 isto deve fazer é pedir um certificado de cliente (opcionalmente) e prosseguir. 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, ele deverá ser redirecionado para link

Até agora, isso funciona bem. No entanto, recebi reclamações de usuários de Mac que navegavam em meu site com o Safari, pois continuavam sendo solicitados pelo certificado quando navegavam no link , enquanto, por exemplo, O Firefox só pergunta ao navegar pelo link ou link .

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

a. Eu não posso ter dois frontends ouvindo na porta 443 com apenas um IP público b. Ainda não encontrei um jeito de dizer "use_frontend if domain_www" ou algo parecido. (Use use_backend ou use-server)

Eu também tentei fazer isso 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 alcança o navegador. De alguma forma, o haproxy-sni elimina 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 conseguir encontrar uma solução melhor).

De preferência eu gostaria de algo assim (confeccionado ... 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
  ...

Espero que alguém possa me ajudar com isso ...

    
por mohrphium 27.01.2015 / 12:51

1 resposta

10

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

A maneira como eu fiz isso, foi criar um frontend para cada domínio que exigisse diferentes configurações de SSL. Em seguida, defino a opção de ligação dessas interfaces para portas altas (elas não podem ser acessadas do público!).

Eu criei outro frontend escutando na porta: 443 para dividir o tráfego baseado em SNI, e configure os servidores backend para 127.0.0.1:highport.

Desta forma, 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 da 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 pensamentos sobre isso, ou qualquer ideia de por que isso pode ser uma má ideia, por favor me avise. Funciona, mas estou me perguntando por que use_frontend não é uma opção. Talvez porque seja algo que não deveria ser feito por qualquer motivo.

    
por 31.01.2015 / 11:29

Tags