私は2つのサイト用にHAProxyを持っています。1つはパブリックで、もう1つはプライベートです。
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
これまでのところ、これは正常に動作します。しかし、Safariでサイトを閲覧しているMacユーザーから、閲覧時に証明書の入力を求められ続けるという不満がありました 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
もちろん、それはうまくいきません
a。パブリックIPが1つしかないポート443で2つのフロントエンドをリッスンすることはできません。 「use_frontend if domain_www」またはそのようなものを言う方法をまだ見つけていません。 (use_backendまたはuse-serverのみ)
3台の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設定を必要とするドメインごとにフロントエンドを作成することでした。次に、これらのフロントエンドのバインドオプションを高ポートに設定します(これらはパブリックからは到達できません!)。
ポート: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がオプションではないのかと思います。多分それは何らかの理由でやるべきではないことだからです。
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
セキュリティに関する注意:HTTPホスト名ではなく、常に(機密)ホスト名をSNI ssl_fc_sni
と照合します。それ以外の場合、攻撃者はwww.example.org
のTLS SNIを送信してクライアント証明書認証をバイパスする可能性がありますが、HTTPホスト名をprivate.example.org
!に設定します。