はじめに
AzureにはAzure Application Gatewayと呼ばれるL7ロードバランサがあります。(以降AppGWと呼びます。)
L7ロードバランサとはL7レイヤのヘッダの中身を見て、宛先を振り分ける機器です。
ロードバランサというと負荷分散のイメージですが、L7レイヤのロードバランサではアクセスしてきたドメイン毎に宛先を振り分ける事も可能です。
シナリオ
今回は一般ユーザがアクセスするWEBページと管理者がアクセスするWEBページを別ドメイン別VMを立てて構築します。フロント側にAzure Application Gatewayを導入する事で、外部からのアクセスを一元管理でき、証明書を持たせてSSL/TLSを終端させたり、WAF機能によりセキュリティ対策を行う事が可能になります。
※証明書及びWAF機能は今回の記事では取り扱いません。
目次
- 構成の説明
- 動作イメージ
- 構築
- トラブルシューティング
- 今後の記事予定
構成の説明
ユーザ用のVMと管理者用のVMがあり、それぞれ別のドメイン名でアクセスします。
example.com => User-AP
admin.example.com => Admin-AP
AppGWは一番フロント側にあり、アクセスされたドメインを見て宛先のVMに転送します。
動作イメージ
実際にAppGWが何をやっているかというと、変換ルールに従ってIPアドレス(送信元、宛先)の付け替えを行っています。送信元IPアドレスを自分のLocalアドレスに変更し、宛先IPアドレスを振り分け対象のLocalアドレスに変換しています。
IPアドレス10.10.10.10のユーザが、example.comにアクセスする場合を見て見ましょう。
1.example.comをDNS解決し、宛先IPアドレスをAppGWのglobalアドレスにセットする。※ドメインはAzureのDNSゾーン機能、もしくは他者のDNSサーバーに登録しておく必要があります。
2.データを受け取ったAppGWは自分宛のデータだと判断し、変換ルールを参照します。変換ルールには、アクセスされたドメインがexample.comの場合、宛先VMをUser-APにするとあるので宛先IPアドレスをUser-APのLocalアドレスである192.168.2.4に付け替えます。また、この際に戻りの通信が自分に戻ってくるように送信元IPアドレスを自分のLocalアドレスである192.168.4.xに付け替えます。※この第四オクテットは、セッションによって変更されるのか、変動します。
3.AppGWは新しい宛先IPアドレスの192.168.2.4を自分のIPルーティングテーブルを参照し転送します。※実際にAppGWのIPルーティングテーブルは参照できないので、ここでは想定で192.168.4.1をネクストホップにしています。
4.データを受け取ったAzure内部の仮想ルータは自分のルーティングテーブルを参照して、User-APがいる192.168.2.0/24側へデータを転送します。※実際に仮想ルータのIPルーティングテーブルは参照できないので、ここでは全てのLocalNWに直接接続している想定にしています。
5.User-APがデータを受け取り、レスポンスを返します。返す先はAppGWのLocalアドレスである、192.168.4.xになります。User-APはデフォルトルートのネクストホップが192.168.2.1であるため、仮想ルータにデータを送ります。
6.仮想ルータがデータを転送し、AppGWのLocalアドレスにデータが到着します。
7.データを受け取ったAppGWは自分宛のデータだと判断し、変換前の送信元IPアドレスを見て、宛先IPアドレスを10.10.10.10に変換し送信元IPアドレスを自分のglobalアドレスに変換しインターネット側へ転送します。
8.ユーザはAppGWの裏にあるVMを意識せずにデータのレスポンスを受け取ります。
一つ一つ見ていくと量が多いように見えますが、要はAppGWでやっていることは変換ルールに沿って、IPアドレスのヘッダを変更しているんですね。
構築
さてここからは実際にAzureのポータル画面からAppGWを構築していきますが、その前に構築のイメージを説明します。
AppGWでは大きく
0.AppGW自体の設定
1.フロント側の設定
2.バックエンド側の設定
3.フロント側とバックエンド側を結びつけるルール
の3つから構成されています。
0.AppGW自体の設定
■レベル
V1かV2か、WAFありか無しかが選べます。V2が推奨です。※WAFは後から変えられますが、V1、V2は後から変更できないため注意。
■自動スケール、最小インスタンス数、最大インスタンス数
トラフィックに応じて、自動的に負荷分散対象のVMを増やしたり減らしたりします。※その分のVMは事前にバックエンドプールとして指定しておく必要があります。特に指定がない場合は最小インスタンス0で指定でOKです。
■HTTP2
基本有効でOKです。
■仮想ネットワーク/サブネット
AppGWを配置する仮想ネットワークを指定します。※AppGW以外(VMなど)が配置されている仮想ネットワークを指定する事はできないので、専用のものを準備しましょう。
1.フロント側の設定
パブリックにし、パブリックIPアドレスを新規または、既存のものを指定します。
2.バックエンド側の設定
振り分け対象毎にバックエンドプールをを作成します。バックエンドプールの追加を押し、追加をおこなっていきます。
■ターゲットの種類
仮想マシンを選び、ターゲットに対象のVMを指定します。
user用、admin用のバックエンドプールを作成し次に進みます。
3.フロント側とバックエンド側を結びつけるルール
さて、ここまで出来たら最後の難関紐づけるルールを設定していきます。ルーティング規則の追加をクリックして、user用のルール、admin用のルールを作っていきます。
■優先度
優先度小さい値から適応されます。複数のルールで重複しない数値を入力します。
<リスナータブ>
リスナーとは、フロント側のルールになります。今回はアクセスされるドメイン毎に振り分けを行いたいので以下設定が必要になります。
■リスナーの種類
マルチサイトにします。一つのリスナーに複数のドメインを登録する場合は、複数またはワイルドカードを指定します。※一つの場合でも今後を見越して複数またはワイルドカードにしておいても問題ありません。
■ホスト名
実際のドメインを指定します。
そのままバックエンドターゲットタブをクリックします。
<バックエンドターゲットタブ>
バックエンド側のルールになります。
■バックエンドターゲット
既に作成済みのバックエンドプールから選択します。
■バックエンド
設定新規に作成します。
■バックエンドプロトコル
HTTPかHTTPSを選択します。
AppGW側で証明書を持つ場合はHTTPを、VMそれぞれが証明書を持つ場合はHTTPSを選択します。
※今回はAppGWもVMもHTTPで設定します。
■その他設定
特殊な用件がない限り変更無しでOKです。
追加すると、ルールに追加されます。
user分のルールに加えてadmin分のルールも同じ要領で追加します。
■タブ 今回は割愛します。
最後の確認及び作成で、作成を押せば完成です。お疲れ様でした。
実際に振り分けられているか確認。
User-APには、User用のindexページ、Admin-APにはAdmin用のindexページを置いて確認してみます。
userドメイン(サブドメイン無し)でのアクセス
adminドメイン(サブドメインadmin)でのアクセス。
ちゃんと振り分けられている事が確認できました。
トラブルシューティング
AppGWを構築して、実際にWEBページにアクセス出来ない時に何から調べればよいでしょうか。
AppGWのトラブルシューティングはDNS周りの問題、AppGWの問題、サーバー側の問題と登場人物が多いため解決には切り分けが重要です。ここでは自分がハマったこととトラブルシューティングの切り分けについて説明します。
サーバーまで来てるか
サーバー側でパケットをモニタリングし、実際の通信がサーバー側まで来ているか確認します。
azureuser@xxxxxx-dev-user-vm:~$ sudo tcpdump port 80 and not host 169.254.169.254 and not host 168.63.129.16
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
08:37:48.553575 IP 192.168.4.7.54236 > 192.1682.4: Flags [P.], seq 953423161:953423920, ack 3598956015, win 63, options [nop,nop,TS val 3888011817 ecr 1494103138], length 759: HTTP: GET / HTTP/1.1
08:37:48.553649 IP 192.1682.4 > 192.168.4.7.54236: Flags [.], ack 759, win 501, options [nop,nop,TS val 1494138472 ecr 3888011817], length 0
08:37:48.553862 IP 192.1682.4 > 192.168.4.7.54236: Flags [P.], seq 1:190, ack 759, win 501, options [nop,nop,TS val 1494138472 ecr 3888011817], length 189: HTTP: HTTP/1.1 304 Not Modified
08:37:48.554324 IP 192.168.4.7.54236 > 192.1682.4: Flags [.], ack 190, win 63, options [nop,nop,TS val 3888011818 ecr 1494138472], length 0
08:37:53.503603 IP 192.168.4.7.54184 > 192.1682.4: Flags [F.], seq 1115436196, ack 1681953072, win 63, options [nop,nop,TS val 3888016767 ecr 1494083421], length 0
08:37:53.503739 IP 192.1682.4 > 192.168.4.7.54184: Flags [F.], seq 1, ack 1, win 507, options [nop,nop,TS val 1494143422 ecr 3888016767], length 0
08:37:53.504301 IP 192.168.4.7.54184 > 192.1682.4: Flags [.], ack 2, win 63, options [nop,nop,TS val 3888016768 ecr 1494143422], length 0
tcpdumpコマンドでパケットキャプチャを行う事ができます。
portオプションでポート番号、hostオプションでIPアドレスでフィルターをかける事ができます。またnotオプションでその通信を含まないというフィルターもかける事ができます。
169.254.169.254と168.63.129.16はどうやら死活監視に使われているようなので除外して80番ポートをモニタしました。
上記の例では、AppgwのLocalネットワーク(192.168.4.0/24)からの通信があるためサーバーまで通信が届いている事がわかります。
もしここまで通信が来ていてWEBページが見えていないのであれば、VM側の問題が疑われます。もしここまで通信が来ていないのであればこれ以前、NSGやAppGW、またそれ以前の問題が疑われます。
AppGWまで来てるか
AppGWの概要というところで、AppGW側に通信が来たかどうかを確認できます。
※実際はタイムラグがあるので通信から数分またないと表示されない。
もしここまで通信が来ていてWEBページが見えていないのであれば、AppGWの設定またはVM側の問題が疑われます。もしここまで通信が来ていないのであればこれ以前、DNSやクライアント側の問題が疑われます。
DNSサーバーでドメインが登録されているか
xxx@MacBook-Pro ~ % nslookup xxx-xxx-dev.com
Server: xxx.139.8.202
Address: xxx.139.8.202#53
Non-authoritative answer:
Name: xxx-xxx-dev.com
Address: yyy.210.206.227
xxx@MacBook-Pro ~ %
xxx@MacBook-Pro ~ % nslookup -type=ns xxx-xxx-dev.com
Server: xxx.139.8.202
Address: xxx.139.8.202#53
Non-authoritative answer:
xxx-xxx-dev.com nameserver = ns3-06.azure-dns.org.
xxx-xxx-dev.com nameserver = ns4-06.azure-dns.info.
xxx-xxx-dev.com nameserver = ns1-06.azure-dns.com.
xxx-xxx-dev.com nameserver = ns2-06.azure-dns.net.
Authoritative answers can be found from:
ns1-06.azure-dns.com internet address = 40.90.4.6
ns2-06.azure-dns.net internet address = 64.4.48.6
ns3-06.azure-dns.org internet address = 13.107.24.6
ns3-06.azure-dns.org has AAAA address 2a01:111:4000:700::6
ns4-06.azure-dns.info internet address = 13.107.160.6
クライアント側の端末からnslookupコマンドで、ドメインの登録状況を確認できます。
オプション無しで実行すると、そのドメインに該当するIPアドレスが(yyy.210.206.227)
オプションで-type=nsを指定すると、登録しているDNSサーバーが確認できます。
閲覧端末側の問題
先にいうと今回はこれが原因でWEBの閲覧が失敗していました。閲覧している端末のChromeブラウザのDNSキャッシュが残っていて、古い情報を参照していました。
自分の端末側の問題で切り分ける際には
・違うブラウザで試してみる(今回ならsafariなど)
・違うPCで試してみる
・違うネットワークで試してみる
などを試す事ができます。
トラブルシューティングの基本は、自分に近いところから切り分けるという大前提があり今回はそれを忘れていたため一番遠いサーバー側から調べて解決まで時間がかかってしました。今後の教訓にしていこうと思います。
今後の記事予定
AppGWに証明書を持たせて、SSL/TLS通信を終端しVM側に証明書を持たせない構成にしていきたいと思います。
また、AppGW配下のVMがNTPやP2Pなど自分から発信を行う場合どのような通信経路になるかも検証していきたいと考えています。