クラウドインテグレーション2部技術3課の山下です。
Network Load Balancer(以下、NLB)をあまり使ったことがなかったので、 今回、改めて、必要な設定や動作について確認してみました。
- (前提)今回の構成と設定
- はじめに結論
- EC2からクライアントPCへ通信を返すために、NAT Gateway・クライアントPC向けのルーティング設定は不要。
- EC2のセキュリティグループ
- EC2のtcpdumpでは、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
- VPC Flow Logsでも、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
- まとめの図
- おわりに
(前提)今回の構成と設定
パブリックサブネットに「internet-facing」のNLBを配置し、プライベートサブネットにEC2を配置します。 クライアントPCからインターネット経由でSSHでアクセスしてみます。
NLBの待ち受けポート番号は51512として、ターゲットグループにはEC2(TCP22番ポート)を設定します。
ヘルスチェックはトラフィックと同じTCP22番ポートを使用します。
ターゲットタイプはインスタンスに設定しています。
※ターゲットタイプをIPアドレスに設定した場合は挙動が変わりますのでご注意ください。詳細は以下リンクに記載があります。
ターゲットをインスタンス ID で登録すると、クライアントの送信元 IP アドレスが保持され、アプリケーションに提供されます。ターゲットを IP アドレスで登録する場合、送信元 IP アドレスはロードバランサノードのプライベート IP アドレスとなります。
はじめに結論
今回の確認の結果は、以下の通りとなりました。(ターゲットグループのタイプが「インスタンス」の場合)
- EC2からクライアントPCへ通信を返すために、NAT Gateway・クライアントPC向けのルーティング設定は不要。
- EC2のセキュリティグループでは、以下の許可が必要。
- NLBのプライベートIPからのSSH通信(ヘルスチェック用)
- クライアントPCのIPからのSSH通信(メイントラフィック用)
- EC2のtcpdumpでは、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
- VPC Flow Logsでも、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
EC2からクライアントPCへ通信を返すために、NAT Gateway・クライアントPC向けのルーティング設定は不要。
今回EC2はプライベートサブネットに配置していますが、NAT Gatewayを設置せずにクライアントPCに通信を返すことができました。 また、プライベートサブネットのルートテーブルにはインターネット向けのルートがありませんが、これも問題ありませんでした。
以下リンクの記載の通り、EC2からの戻りの通信がNLBを経由しているため、このような挙動となるようです。
https://aws.amazon.com/jp/blogs/news/webinar-bb-elastic-load-balancing-2019/
NLB は上記の1つの目のご質問の回答に書いた AWS Hyperplane という技術によりパケットの帰りにおいてもNLBを通過します。 AWS Hyperplane は Source IP が Client の IP になっていても VPC 内で戻りのパケットが正しくNLB に到達するように機能します。 その証拠にクライアント側からパケットを見ると NLB と直接通信しているように見えます。 また、バックエンドのサーバー側でルーティングを意識する必要はございません。ただし、バックエンド側のセキュリティグループの設定でクライアント側の IP(Internet-facing の場合、多くは0.0.0.0/0を設定)との通信を許可する必要があります。
ただし、パッケージのダウンロードなど、EC2発のリクエストをインターネット側に出す場合は、NAT Gatewayおよびインターネット向けのルーティングが必要となります。
EC2のセキュリティグループ
NLBのプライベートIPからのSSH通信(ヘルスチェック用)
ヘルスチェック用に、NLBのプライベートIPからのSSH通信を許可する必要がありました。 ※NLBにはセキュリティグループを設定できないため、直接IPを指定しています。今回はNLBに固定IPを設定しなかったので、ネットワークインターフェイスの画面からIPを確認しました。
クライアントPCのIPからのSSH通信(メイントラフィック用)
以下リンクの通り、クライアントのIPからの通信を許可する必要があります。
注意点として、送信元IPはクライアントPCのIPアドレスになるのですが、ポート番号はNLBのリスナーポート(51512)ではなく、ターゲットグループの待ち受けポート(22)になります。
NLBは送信元IPは透過させますが(ターゲットタイプがインスタンスの場合)、宛先ポート番号はリスナールールに従って変換します。
上記を踏まえたうえで、以下のようなセキュリティグループを設定しました。
EC2のtcpdumpでは、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
以下はEC2でtcpdumpを実行した際のログです。
[ec2-user@ip-10-0-128-108 ~]$ sudo tcpdump -n port 22 -A | head tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 03:20:59.752727 IP 10.0.128.108.ssh > 114.xxx.xxx.xxx.65367: Flags [P.], seq 2090933415:2090933531, ack 486427986, win 945, length 116 E.....@...|i ..lrE q...W|.....MRP..........`.`n6....$.....Q...n.D..I&..|..V...,.Z...D......[-%.....kB.."7F".B...^...[..^;`,o.J#.H6"..U....j.Y..1..; .L..E. . 03:20:59.752839 IP 10.0.128.108.ssh > 114.xxx.xxx.xxx.65367: Flags [P.], seq 116:232, ack 1, win 945, length 116 E.....@...|h ..lrE q...W|.....MRP..........`.........?=4.(W.}Qw..5.vB..G.>.?......Z7.[=..v.qb.u....f.A. ...y7u... .q..L....EZ..N.. y@....#cI....V..[1.b...2. 03:20:59.802469 IP 114.xxx.xxx.xxx.65367 > 10.0.128.108.ssh: Flags [.], ack 232, win 508, length 0 E..(..@.i.q.rE q tcpdump: Unable to write output: Broken pipe [ec2-user@ip-10-0-128-108 ~]$ exit
見づらくて申し訳ありませんが、送信元と宛先のIPアドレスが記載されているのが分かるかと思います。 10.0.128.108がEC2のIPアドレス、一部マスキングしていますが114.xxx.xxx.xxxがクライアントPCのIPアドレスです。
VPC Flow Logsでも、送信元IPアドレス:クライアントPC、宛先ポート番号:22番ポートの通信として記録される。
VPC Flow LogsをCloudWatch Logsに出力し、EC2に紐づいているネットワークインターフェイスのログを確認しました。 以下のフィルターパターンで、送信元IP:クライアントPC、宛先ポート番号:22、プロトコル:TCPでフィルターしています。
[version, account, eni, source="114.xxx.xxx.xxx", destination, srcport, destport="22", protocol="6", packets, bytes, windowstart, windowend, action, flowlogstatus]
クライアントPCのIPでフィルターしないと、NLBからのヘルスチェック通信が大量にヒットして、目的の通信を探すのが困難になります。 なお、VPC Flow Logsのフィルター方法の詳細については、以下ブログでもご案内していますのでよろしければご参照ください。
VPC Flow Logs(CloudWatch Logs)を閲覧時にフィルタする方法 - サーバーワークスエンジニアブログ
フィルターした結果、クライアントPCからのSSHリクエストが許可されているログが確認できました。
まとめの図
これまでの設定と、送信元/宛先アドレスの状態の変化をまとめると、下図のようになりました。 ※well-knownポート以外のポート番号を使うケースについては、便宜上「Un-Wellknown」としました。
おわりに
以上、NLBを使用する場合の設定と動作の確認でした。(ターゲットタイプがインスタンスの場合のみですが)
基本的な事ではありますが、戻りの通信がNLBを経由するのかどうか、セキュリティグループで許可する通信は何か等、意外と理解があやふやだったので、今回しっかり確認することが出来て良かったです。
この記事が少しでも参考になれば幸いです。
山下 祐樹(執筆記事の一覧)
2021年11月中途入社。前職では情シスとして社内ネットワークの更改や運用に携わっていました。 2023 Japan AWS All Certifications Engineers。