web-dev-qa-db-fra.com

Haproxy avec sni et différents paramètres SSL

J'ai Haproxy pour mes deux sites, l'un d'eux public et un privé.

www.mysite.com privé.mysite.com

ATM, j'utilise haproxy comme ceci:

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

Ce que cela devrait faire est de demander un certificat client (éventuellement) et de continuer. Si le domaine n'est pas www.example.com et que le visiteur ne peut pas fournir le bon certificat ni le chemin est/Ghost/et le visiteur ne peut pas fournir le bon certificat, il devrait être redirigé vers HTTPS: //www.example .com

Jusqu'à présent, cela fonctionne bien. Cependant, j'ai eu des plaintes par les utilisateurs de Mac parcourant mon site avec Safari qu'ils continuent à demander le certificat lorsqu'il navigue sur https://www.example.com/ tandis que, par exemple, Firefox ne demande que lors de la navigation. https://private.example.com/ ou https://www.example.com/ghost/ .

Il s'agit de ce que Safari fonctionne donc donc je ne peux pas résoudre ce problème. Mon idée était d'utiliser SNI pour diviser entre différentes fronçons

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

Bien sûr que cela ne fonctionne pas parce que

une. Je ne peux pas avoir deux frontes à écouter sur le port 443 avec une seule pivité publique b. Je n'ai pas encore trouvé de chemin à dire "use_frontend si domain_www" ou quelque chose comme ça. (Seulement utiliser_backend ou use-serveur)

J'ai aussi essayé de le faire avec trois serveurs 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

Cela fonctionne, cependant, le problème est que Haproxy-Private demande le certificat client, mais la demande n'atteint pas le navigateur. D'une manière ou d'une autre haproxy-sni abandonne la demande.

De plus, je dispose maintenant de trois serveurs haproxy qui n'est pas souhaitable (bien qu'une possible option si je ne trouve pas de meilleure solution).

De préférence, je voudrais quelque chose comme ça (maquillé .. ne connaissez pas les véritables options)

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

J'espère que quelqu'un peut me aider...

8
mohrphium

J'ai trouvé une solution à ce problème, cela ne nécessite pas de serveurs ou de services supplémentaires. Je ne suis pas totalement sûr que cela n'accorde pas de nouveaux problèmes cependant. Pour moi, il semble fonctionner en ce moment.

La façon dont je l'ai fait, était de créer un frontend pour chaque domaine nécessitant différents paramètres SSL. J'ai ensuite défini l'option Bind de ces fronctions à des ports élevés (ceux-ci ne sont pas accessibles de public!).

J'ai créé une autre écoute de frontend sur le port: 443 pour diviser le trafic basé sur SNI et définir les serveurs de backend au 127.0.0.1:High-port.

De cette façon, j'ai créé une sorte de boucle dans haproxy

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

Voici la partie de configuration.

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

Si quelqu'un a des idées à ce sujet, ou une idée de la raison pour laquelle cela pourrait être une mauvaise idée s'il vous plaît faites le moi savoir. Cela fonctionne, mais je me demande pourquoi utiliser_frontend n'est pas une option. Peut-être parce que c'est quelque chose qui ne devrait pas être fait pour les raisons.

13
mohrphium

les versions récentes de Haproxy supportent un paramètre appelé crt-list qui vous permet de spécifier différents paramètres TLS en fonction du certificat correspondant

vous pouvez l'utiliser comme ceci:

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

plus d'infos: https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list

nOTE SUR LA SÉCURITÉ: Faites toujours correspondre vos noms d'hôte (sensibles) contre Sni ssl_fc_sni, pas le nom d'hôte http. Sinon, un attaquant pourrait éventuellement contourner votre authentification de votre client en envoyant la SNI TLS de www.example.org Mais définissez le nom d'hôte HTTP sur private.example.org!

3
freaker