AFD + AppGW の構成で考える アクセス先 と SNI と ホストヘッダー の関係
証明書のエラー や ホスト名の不一致 の問題が起こっている...
Azure Front Door も Application Gateway も、構成によっては、証明書のエラー や、ホスト名の不一致によるリダイレクトの問題に直面することがあります。
バックエンド(アクセス先)の指定の仕方、Server Name Indication ( SNI )、HTTP ホストヘッダー がわからん、という感じです。
たとえば Azure Front Door の トラブルシューティングのページ に、証明書の検証についての記載があります。
Server Name Indication (SNI) についても言及されています。
また、Azure Front Door も Application Gateway もどちらもリバースプロキシですが、「リバース プロキシとそのバックエンド Web アプリケーションの間で、元の HTTP ホスト名を維持する」といったドキュメントがあります。HTTP ホストヘッダー の書き換えについて言及がされています。
アクセス先、Server Name Indication ( SNI )、HTTP ホストヘッダー
このあたり非常に混乱しやすいので、私自身のお勉強をかねて少し整理をしてみたいと思います。
以下のような、Azure Front Door と Application Gateway を組み合わせた構成を例に、考えてみます。
なお、こちらが非常に良くまとまっており参考になりました。
- HTTP ホストヘッダーと TLS の SNI について
- HTTP の概要 - HTTP | MDN - Mozilla Developer
- TLS・SSLハンドシェイクの 仕組みは? | Cloudflare
- TLS/SSL ハンドシェイクとは何ですか?| デジサートの FAQ
基礎知識 と パケットキャプチャによる確認
さて、少し整理をしてみます。
基礎中の基礎からですが、まずは OSI参照モデルで L1 - L7 までの階層が説明されていることを思い出してみます。
手元のPC から Azure Front Door への通信する場合のながれを考えてみると、
まずは WEB ブラウザに入力したURL (例:https://www.contoso.com) より、www.contoso.com の部分が DNS サーバーによって Azure Front Door の IPアドレスに名前解決され、PC -> Azure Front Door への通信が開始されます。L3 のやり取りです。
その後、 L4 - L7 のやり取りとして、概ね以下のような流れがおこります。
- L4 のプロトコルである TCP での 3ハンドシェイク(SYN, SYN-ACK, ACK) が行われ、TCPセッションが確立されます。
- 続いて、L5-L6 にあたる SSL/TLS での TLSハンドシェイクが行われ、暗号スイートの合意やTLS/SSL証明書の確認、シークレットの交換が行われたのちに、セッションキーを用いて暗号化された通信が行われます。なお図中 青★ をつけた箇所では、バックエンドから提示されたTLS/SSL証明書が問題ないものか、検証されます。
- L7 の HTTPS は、HTTP同様 GET / POST などのリクエストを送信します。サーバーは Resoinse を返します。それらの通信は全て、セッションキーを用いて暗号化されています。
このあたり、少しパケットもキャプチャして、確認してみました。
手元のPC (192.168.11.37) から Azure Front Door (www.sample01.uuesama.com )に対してのアクセスを行い、キャプチャした結果が以下です。
少し詳しく見てみます。
TCP three-way handshaking
まずは、Azure Front Door (www.sample01.uuesama.com) に対して、最初のパケットを投げている部分です。
当然ながら、ブラウザで www.sample01.uuesama.com へアクセスするよう指示しても、DNSによって名前解決された結果のIP (今回だと、13.107.238.46 ) に対しての通信が開始されています。
手元のPCからの最初のパケットは、TCP SYNパケット の送信です。
Azure Front Door からの応答 TCP SYN/ACKパケットが返されています。
最後に再び手元のPCからのTCP ACKパケットが送信され、ハンドシェイク(SYN, SYN-ACK, ACK) が完了し、TCPセッションが確立されています。
TLS handshake
TCPセッションが開かれた後、続けて TLS handshake プロセスが始まります。
まず、手元PCから Client Hello が送信されています。
キャプチャ左下が、Client Hello のパケット内を確認してみた結果ですが、Server Name Indication が入っていることもわかります。
今回の例だと、 www.sample01.uuesama.com です。
さて、Azure Front Door は共用のリソースであり、様々なお客様のWEBサイトを提供しています。
ここまで、手元PCからの TCPのセッションは、Azure Front Door のグローバルIP(今回だと、13.107.238.46 ) に対して確立されましたが、
Server Name Indication として www.sample01.uuesama.com が示されたことにより、Azure Front Door はこのドメインに対応した証明書を応答する必要があることを理解します。
Azure Front Door は、Server Hello を返しており、続けて、SNI を元に Certificate も提示しています。
こちらもパケット内、Certificate の箇所を確認すると、 CN= *.sample01.uuesama.com と、しっかり対応する証明書が返されています。
クライアントPは受け取った証明書を検証をし、問題が無ければ、ハンドシェイクのプロセスを進めます。
HTTPS Request/Response
以降のやりとりはしっかりと暗号化されています。
どういったやり取りなのかは、パケットキャプチャしても追うことができません。
そこで、 Azure Front Door のログを確認してみます。
GET リクエストを受け取っており、クライアントからの要求ホスト名が www.sample01.uuesama.com であることや、
バックエンドとして設定している Application Gateway に対して接続を行っていることが確認できます。
ログの各項目の意味は Azure Front Door でのメトリックとログの監視 | アクセス ログ を参照します。
End to End での アクセス先 / SNI / HTTP ホストヘッダー の関係 はどうなっているか?
さて、手元のPC から Azure Front Door への流れは確認できました。
同じやり取りが、Azure Front Door と Application Gateway の間で、また、Application Gateway と バックエンドの間でも、行われています。
前半で示した構成例を元に、考えてみます。
アクセス先の指定の仕方 と 実際の接続先
クライアントPC から Azure Front Door に対しての通信は、WEBブラウザに FQDN で接続先を指示することで開始されますが、
実際には、DNSによって名前解決された結果のIPに対しての通信が開始されるということは、前述の通りです。
これは、Azure Front Door や Application Gateway でも同様です。
Azure Front Door の設定 [ホスト名] の箇所で、バックエンドとして Application Gateway を FQDN で指定しました。
Azure Front Door はこれを名前解決した結果得られた IPアドレス へ、アクセスしてTCPセッションを確立します。
Application Gateway も、バックエンド ターゲット を AppSrervice の既定のドメイン xxx.azurewebsites.com を使用して指定しています。
Application Gateway もこれを名前解決した結果得られた IPアドレス へ、アクセスしてTCPセッションを確立します。
Server Name Indication ( SNI )
Azure Front Foor は、指定した [ホスト名] を SNI として利用します。
今回の例では、バックエンドとして Application Gateway を appgw.contoso.com という形で指定していますので、これが SNI として利用されます。
ドキュメントとしては Azure Front Door を使用したエンド ツー エンド TLS | 配信元 TLS 接続 (Azure Front Door から配信元) あたりに言及があります。
HTTPS 接続の場合、Azure Front Door では、サブジェクト名が配信元の "ホスト名" と一致する、有効な証明機関 (CA) からの証明書を提示することを配信元に要求します。
Application Gateway が Azure Front Door へ返す証明書や、バックエンドとの間で利用する SNI は、いろいろなパターンがあります。
例えば、Basic リスナー で構成されている場合には、Azure Front Door には基本リスナーで構成されている証明書が返されます。
また SNI は、バックエンドに対してのライブ トラフィックでは、HTTP 設定からホスト名が設定され、xxx.azurewebsites.com となります。
このあたりは Application Gateway の構成により変化するかと思いますので、詳しくは Application Gateway での TLS 終端とエンド ツー エンド TLS の概要 | v1 SKU と v2 SKU における SNI の違い を確認してください。
ちなみに、実際構築してみてこのあたりが上手くいかない場合には、以下の情報が参考になります。
HTTP ホストヘッダー
HTTPホストヘッダーの上書きについては、公開ドキュメント や、以下サポートブログに、発生しうる問題と共に、良くまとまっています。
今回の構成例では、Azure Front Foor、Appliation Gateway ともに、上書きをしない構成としておきました。
Azure Front Foor では [配信元のホストヘッダー] を空欄にし、HTTP ホストヘッダー を上書きしない構成とします。
Appliation Gateway でも、[新しいホスト名でオーバーライドする] を OFF にして、上書きしない構成とします。
これによりHTTP ホストヘッダー は、一貫して www.contoso.com となります。
まとめると
まとめると、今回考えてみた例では、アクセス先の指定、SNI、HOSTヘッダーの関係は、それぞれ次のような形になると思われます。
-
①クライアント - Azure Front Door
- アクセス先 = www.contoso.com
- Server Name Indication = www.contoso.com
- HTTP ホストヘッダー = www.contoso.com
-
②Azure Front Door - Application Gateway
- アクセス先 = appgw.contoso.com
- Server Name Indication = appgw.contoso.com
- HTTP ホストヘッダー = www.contoso.com ( [配信元のホストヘッダー] を空欄とし、書き換えを行っていないため)
-
③Application Gateway - AppSerivce
- アクセス先 = xxx.azurewebsites.com
- Server Name Indication = xxx.azurewebsites.com ( ライブトラフィックの場合 )
- HTTP ホストヘッダー = www.contoso.com ( ホスト名のオーバーライドを設定していないため)
リバースプロキシが多段になることで、頭がこんがらがっていましたが、図にしてみて少し整理できた気がします。
なるほど。
むずかしそ。 AFD + AppGW の構成ってそもそも必要なのか。
ずばりな QA が こちら にあります。
また、負荷分散のオプション というページに、使い分けや併用のディシジョンツリー等があったりします。
お最近は AFD → Origin の部分をプライベートエンド経由で通信させることもでき、パブリックアクセス不要に出来たりしますので、AFD のみでよいとか、いろいろあるかもですね。
AFD + AppGW の構成が必要なのか。
不要なら、シンプルな構成が一番だと思います。
参考リンク
Discussion