具有 SNI 和不同 SSL 設置的 HAProxy
我的兩個站點都有 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 ...
我希望有人可以幫助我解決這個問題…
我找到了解決這個問題的方法,不需要額外的伺服器或服務。我不完全確定這是否不會產生新問題。對我來說,它現在似乎有效。
我這樣做的方式是為需要不同 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 不是一個選項。也許是因為無論出於何種原因,這是不應該做的事情。