두 사이트에 대해 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_sni
HTTP 호스트 이름이 아닌 SNI 에 대해 (민감한) 호스트 이름을 일치시킵니다 . 그렇지 않으면 공격자가 TLS SNI를 전송하여 클라이언트 인증서 인증을 무시 www.example.org
하고 HTTP 호스트 이름을 private.example.org
!