HAProxy с SNI и другими настройками SSL

9

У меня есть HAProxy для моих двух сайтов, один из них публичный и один частный.

www.mysite.com private.mysite.com

Atm, я использую 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

Конечно, это не работает, потому что

а. У меня не может быть двух интерфейсов, прослушивающих порт 443 только с одним общедоступным IP-адресом b. Я еще не нашел способ сказать "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
  ...

Я надеюсь, что кто-то может помочь мне с этим ...

mohrphium
источник

Ответы:

13

Я нашел решение этой проблемы, которое не требует дополнительных серверов или услуг. Я не совсем уверен, если это не порождает новые проблемы, хотя. Для меня это похоже на работу прямо сейчас.

То, как я это сделал, заключалось в создании внешнего интерфейса для каждого домена, для которого требовались разные настройки ssl. Затем я установил опцию связывания этих интерфейсов с высокими портами (они недоступны для публики!).

Я создал еще один интерфейсный порт, прослушивающий порт: 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 не вариант. Может быть, потому что это не должно быть сделано по каким-либо причинам.

mohrphium
источник
Хорошая идея. Я также не смог найти документацию по этой настройке. Схожа ли производительность с этим циклом HAProxy?
JB. С моникой.
Извините, я не знаю, насколько это эффективно, потому что A: не использовал его долгое время (из-за исходных ip-фильтров), B: не имеет сайта с высоким трафиком, где оптимизация производительности была бы более интересной ...
морфия
Я просто поставил 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

элт-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!

Freaker
источник
ОП использует один и тот же сертификат для обоих. Вопрос был больше о другой ca-fileобстановке.
gre_gor