はじめに
お疲れ様です。矢儀 @yuki_ink です。
NLB、使ってますか?
AWS Network Load Balancer (NLB) には「クライアントIPアドレスの保持」という機能があります。
この機能を有効にすると、NLB配下のターゲット(EC2など)にクライアントの実IPアドレスが直接届くようになります。
この時、ターゲット側のセキュリティグループではどのような設定を入れておく必要があるでしょうか。
本記事では、NLBの「クライアントIPアドレスの保持」機能について、セキュリティグループの設定の観点から考察します。
「クライアントIPアドレスの保持」機能について
概要
CloudFormationテンプレートだと、TargetGroupAttributes の preserve_client_ip.enabled キーで表現されます。
NLBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: NLBTargetGroup
Protocol: TCP
Port: 8080
HealthCheckProtocol: TCP
HealthCheckPort: 8080
HealthCheckIntervalSeconds: 30
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 3
UnhealthyThresholdCount: 2
VpcId: !Ref VPC
TargetType: ip
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 300
+ - Key: preserve_client_ip.enabled
+ Value: true
この機能を有効にすると、NLBのターゲット(EC2インスタンスなど)に到達するパケットの送信元IPアドレスは、NLBのIPアドレスではなく、実際のクライアントのIPアドレスとなります。
- NLBからターゲットへのヘルスチェックに伴う通信については、NLBのプライベートIPアドレスが送信元IPアドレスとなります
- IPv6からIPv4に変換されたトラフィックについては、送信元IPアドレスは常にNLBのプライベートIPアドレスとなります
「クライアントIPアドレスの保持」機能の有効/無効の比較
次の表は、「クライアントIPアドレスの保持」機能が 有効 になっているときにターゲットが受け取る IP アドレスを示しています。
| ターゲットの種類 | IPv4 クライアントからの通信 | IPv6 クライアントからの通信 |
|---|---|---|
| インスタンス (IPv4) | クライアント IPv4 アドレス | NLB IPv4 アドレス |
| IPアドレス (IPv4) | クライアント IPv4 アドレス | NLB IPv4 アドレス |
| IPアドレス (IPv6) | NLB IPv6 アドレス | クライアント IPv6 アドレス |
次の表は、「クライアントIPアドレスの保持」機能が 無効 になっているときにターゲットが受け取る IP アドレスを示しています。
(そりゃそうじゃ!! という感想です笑)
| ターゲットの種類 | IPv4 クライアントからの通信 | IPv6 クライアントからの通信 |
|---|---|---|
| インスタンス (IPv4) | NLB IPv4 アドレス | NLB IPv4 アドレス |
| IPアドレス (IPv4) | NLB IPv4 アドレス | NLB IPv4 アドレス |
| IPアドレス (IPv6) | NLB IPv6 アドレス | NLB IPv6 アドレス |
出典はこちら。
NLB配下のターゲット側のセキュリティグループで取るべき設定
下図のような環境を想定して、考えてみまます。
Target SG のインバウンド通信の許可設定で、以下の4パターンを試してみました。
| # | インバウンドルールのソース | ClientからTargetへの 通信可否 |
備考 |
|---|---|---|---|
| 1 | Client SG | NG | - |
| 2 | NLB SG | OK!! | - |
| 3 | Client SunbetのIPレンジ | OK!! | サブネットのIPレンジではなくClientインスタンス単体のIPアドレスでも同様の結果に |
| 4 | NLB SubnetのIPレンジ | NG | - |
#1、2がセキュリティグループベースの指定、#3、4がIP(CIDR)ベースの指定となっています。
結果としては、#2 NLB SG と #3 Client SunbetのIPレンジ からのインバウンド許可を設定した場合のみ、ClientからTargetへの通信が可能でした。
IPベースの指定では、NLBではなくClient側を指定しないといけない のは想像通りですが、
セキュリティグループベースの指定では、Clientのセキュリティグループではなく、むしろNLBのセキュリティグループを指定する必要がある という点に、ロマンが詰まっていますね。
たとえ、送信元IPがClientのIPでも(TCP的にはClientが喋っているように見えても)、Targetから見れば、最後にパケットを出しているENIはNLBのものです。
パケットを出したENIとそこに紐づくセキュリティグループまでは流石に偽装できない(させない)という、AWSの思想でしょう。
脳汁が出たところで、セキュリティグループのインバウンドルールの評価方法を復習しておきましょう。
セキュリティグループの評価ルール:
- IPアドレス(CIDR)で許可した場合: パケットの送信元IPアドレスが評価される
- セキュリティグループIDで許可した場合: パケットの送信元ENI(に紐づくセキュリティグループID)が評価される
「クライアントIPアドレスの保持」機能の有効/無効にかかわらず、セキュリティグループベースの許可ルールを書くなら、シンプルにお隣のENI(= NLB)のセキュリティグループを見ましょう、ということになりますね。
まとめ
最後に、AWSのベストプラクティスを見てみます。
「クライアントIPアドレスの保持」機能を有効にするときは、このベストプラクティスに沿って考えましょう!
==========
■ ロードバランサーにセキュリティグループが関連付けられている場合
ロードバランサーに関連付けられたセキュリティグループを参照するルールを追加します。
■ ロードバランサーにセキュリティグループが関連付けられていない場合
クライアントの IP アドレスからのトラフィックを許可するルールを追加します。
==========
出典はこちら。
おまけ:「クライアントIPアドレスの保持」機能の注意事項
公式ドキュメントで、以下の注意事項が案内されています。
クライアントIPアドレスの保持を有効にすると上手く通信できない…という場面には、注意事項に該当していないか確認しましょう。
特に注意したいポイントを抜粋しておきます。
・クライアントIP保持が有効な場合、トラフィックは Network Load Balancer(NLB)からターゲットへ直接流れる 必要があります。ターゲットは、ロードバランサーと同じVPC、または同一リージョン内でピア接続されたVPC内に存在していなければなりません。
・トランジットゲートウェイを経由する場合、クライアントIP保持はサポートされません。
・Gateway Load Balancerエンドポイントを使用して、Network Load Balancerとターゲット(インスタンスまたはIPアドレス)の間のトラフィックを検査する場合、たとえターゲットがNLBと同じVPC内にあっても、クライアントIP保持はサポートされません。
・AWS PrivateLink 経由のインバウンドトラフィックに対しては、クライアントIP保持は影響しません。この場合、送信元IPアドレスは常にNetwork Load BalancerのプライベートIPアドレスになります。
・ターゲットグループに AWS PrivateLink のネットワークインターフェイス、または他の Network Load Balancer のネットワークインターフェイスが含まれている場合、クライアントIP保持はサポートされません。この構成では、これらのターゲットとの通信が失われます。
・IPv6 → IPv4 に変換されたトラフィックに対しても、クライアントIP保持は効果がありません。この場合も、送信元IPアドレスは常にNLBのプライベートIPアドレスになります。

