태그 보관물: haproxy

haproxy

SNI 및 다른 SSL 설정을 사용하는 HAProxy path_beg

두 사이트에 대해 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

물론 작동하지 않기 때문에

ㅏ. 공개 IP가 하나 인 포트 443에서 수신 대기하는 프런트 엔드를 두 대 가질 수 없습니다. b. “domain_www 인 경우 use_frontend”또는 이와 유사한 방법을 아직 찾지 못했습니다. (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가 요청을 삭제합니다.

또한 이제는 바람직하지 않은 3 개의 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
  ...

누군가가 나를 도울 수 있기를 바랍니다 …



답변

추가 서버 또는 서비스가 필요없는이 문제에 대한 해결책을 찾았습니다. 그래도 이것이 새로운 문제를 일으키지 않는지는 확실하지 않습니다. 나를 위해 지금 작동하는 것 같습니다.

내가 한 방법은 서로 다른 SSL 설정이 필요한 각 도메인에 대한 프런트 엔드를 만드는 것입니다. 그런 다음 해당 프런트 엔드의 바인드 옵션을 높은 포트로 설정했습니다 (공개에서 도달 할 수 없음).

SNI를 기반으로 트래픽을 나누기 위해 포트 : 443에서 수신 대기하는 다른 프런트 엔드를 만들고 백엔드 서버를 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 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

보안에 대한 참고 사항 : 항상 ssl_fc_sniHTTP 호스트 이름이 아닌 SNI 에 대해 (민감한) 호스트 이름을 일치시킵니다 . 그렇지 않으면 공격자가 TLS SNI를 전송하여 클라이언트 인증서 인증을 무시 www.example.org하고 HTTP 호스트 이름을 private.example.org!


답변