Amazon Web Services ブログ

Amazon VPC のルーティング強化により、VPC 内のサブネット間のトラフィックが調査可能に

2019 年 12 月以降、Amazon Virtual Private Cloud (VPC)では、すべての入力トラフィック(北-南トラフィック)の特定のネットワークインターフェイスへのルーティングが許可されるようになりました。この機能を使用できる理由は多数あります。たとえば、侵入検出システム(IDS)アプライアンスを使用して着信トラフィックを検査したり、入力トラフィックをファイアウォールにルーティングするために使用します。

この機能を開始して以来、多くのお客様から、VPC 内のあるサブネットから別のサブネットへ流れるトラフィックを分析する同様の機能(East-Westトラフィック)を提供するように依頼がありました。ルーティングテーブル内のルートをデフォルトのローカルルートよりも具体的なものにすることはできないため、今日までは不可能でした(詳細については VPC ドキュメントをチェックしてください)。平易な言い方をするなら、デフォルトのローカルルート(VPC 全体の CIDR 範囲)よりも小さな CIDR 範囲を使用する送信先があるルートはないということです。たとえば、VPC 範囲が 10.0.0/16 で、サブネットに 10.0.1.0/24 がある場合、 10.0.1.0/24 へのルートは 10.0.0/16 へのルートよりも具体的です。

ルーティングテーブルには、この制限はありません。ルーティングテーブル内のルートには、デフォルトのローカルルートよりも詳細なルートを設定できます。このようなより具体的なルートを使用して、すべてのトラフィックを専用のアプライアンスまたはサービスに送信して、2 つのサブネット間で流れるすべてのトラフィック(東西トラフィック)を検査、分析、またはフィルタリングできます。ルートターゲットになる可能性があるのは、構築または取得したアプライアンスに添付されたネットワークインターフェイス(ENI)、パフォーマンスまたは高可用性の理由から、複数のアプライアンスにトラフィックを配信する AWS Gateway Load Balancer(GWLB)エンドポイント、AWS Firewall Managerのエンドポイント、または NAT ゲートウェイです。また、サブネットと AWS Transit Gateway の間にアプライアンスを挿入することも許可します。

アプライアンスをチェーンして、送信元サブネットと送信先サブネット間で複数のタイプの分析を行うことが可能です。たとえば、最初にファイアウォール(AWS管理下またはサードパーティーのファイアウォールアプライアンス)を使用してトラフィックをフィルターし、次にトラフィックを侵入検知および防止システムに送信し、最後にディープパケットインスペクションを実行します。仮想アプライアンスには、 AWS パートナーネットワークと AWS Marketplace からアクセスできます。

アプライアンスをチェーンする場合、各アプライアンスと各エンドポイントは別々のサブネット内に存在する必要があります。

実際にやってみて、この新しい機能を試してみましょう。

仕組み
このブログ投稿では、3 つのサブネットを持つ VPC があると仮定しましょう。最初のサブネットは公開サブネットで、踏み台ホストがあります。2 番目のサブネットの API やデータベースなどのリソースへのアクセスが必要です。2 番目のサブネットはプライベートです。踏み台に必要なリソースをホストします。このセットアップのデプロイに役立つシンプルな CDK スクリプトを作成しました。

VPC のより具体的なルーティング

コンプライアンス上の理由から、当社では、このプライベートアプリケーションへのトラフィックが侵入検出システムを通過することを要求しています。CDK スクリプトは、ネットワークアプライアンスをホストするため、 3 番目のサブネット、プライベートサブネットも作成します。Amazon Elastic Compute Cloud(Amazon EC2)インスタンスは、踏み台ホスト、アプリケーションインスタンス、ネットワーク分析アプライアンスの 3 つを提供します。スクリプトは、アプリケーションインスタンスをブートストラップし、AWS Systems Manager セッションマネージャー (SSM) を使用するため、3つのインスタンスに接続を許可するNATゲートウェイも作成します。

これはデモであるため、ネットワークアプライアンスは IP ルーターとして設定された通常の Amazon Linux EC2インスタンスです。現実では、 AWS Marketplaceまたはゲートウェイロードバランサーのエンドポイント上でパートナーが提供する多数のアプライアンスのいずれか、またはNetwork Firewallを使用する可能性が非常に高いです。

アプライアンスを通してトラフィックを送信するようにルーティングテーブルを変更してみましょう。

AWS マネジメントコンソールまたは AWSコマンドラインインターフェイス (CLI) のいずれかを使用して、 10.0.0.0/24 および 10.0.1.0/24サブネットルーティングテーブルに、より具体的なルートを追加します。これらのルートは、トラフィックインスペクションアプライアンスのネットワークインターフェイスである eni0 を指します。

CLI を使用して、まずアプライアンスの VPC ID、サブネット ID、ルーティングテーブル ID、および ENI ID を収集します。

VPC_ID=$ (aws\
    --region $REGION cloudformation describe-stacks             \
    --stack-name SpecificRoutingDemoStack                       \
    --query "Stacks[].Outputs[?OutputKey=='VPCID'].OutputValue" \
    --output text)
echo $VPC_ID

APPLICATION_SUBNET_ID=$(aws                                                                      \
    --region $REGION ec2 describe-instances                                                      \
    --query "Reservations[].Instances[] | [?Tags[?Key=='Name' && Value=='application']].NetworkInterfaces[].SubnetId"  \
    --output text)
エコー $APPLICATION_SUBNET_ID

APPLICATION_SUBNET_ROUTE_TABLE=$ (aws\
    --region $REGION  ec2 describe-route-tables                                                  \
    --query "RouteTables[?VpcId=='${VPC_ID}'] | [?Associations[?SubnetId=='${SUBNET_ID}']].RouteTableId" \
    --output text)
echo $APPLICATION_SUBNET_ROUTE_TABLE

APPLIANCE_ENI_ID=$ (aws\
    --region $REGION ec2 describe-instances                                                      \
    --query "Reservations[].Instances[] | [?Tags[?Key=='Name' && Value=='appliance']].NetworkInterfaces[].NetworkInterfaceId" \
    --output text)
echo $APPLIANCE_ENI_ID

BASTION_SUBNET_ID=$ (aws\
    --region $REGION ec2 describe-instances                                                     \
    --query "Reservations[].Instances[] | [?Tags[?Key=='Name' && Value=='BastionHost']].NetworkInterfaces[].SubnetId" \
    --output text)
echo $BASTION_SUBNET_ID

BASTION_SUBNET_ROUTE_TABLE=$(aws \
 --region $REGION ec2 describe-route-tables \
 --query "RouteTables[?VpcId=='${VPC_ID}'] | [?Associations[?SubnetId=='${BASTION_SUBNET_ID}']].RouteTableId" \
 --output text)
echo $BASTION_SUBNET_ROUTE_TABLE

次に、さらに特定のルートを 2 つ追加します。1 つのルートは、アプライアンスネットワークインターフェイスを介して、踏み台パブリックサブネットからアプリケーションプライベートサブネットにトラフィックを送信します。 2 番目のルートは、返信をルーティングする方向とは反対方向です。アプリケーションプライベートサブネットから踏み台パブリックサブネットに、アプライアンスのネットワークインターフェイスを介して、より具体的なトラフィックをルーティングします。 混乱していますか? 以下の図表を見てみましょう。

VPC のより具体的なルーティング

まず、踏み台ルーティングテーブルを修正しましょう:

aws ec2 create-route                                  \
     --region $REGION                                 \
     --route-table-id $BASTION_SUBNET_ROUTE_TABLE     \
     --destination-cidr-block 10.0.1.0/24             \
     --network-interface-id $APPLIANCE_ENI_ID

次に、アプリケーションルーティングテーブルを変更しましょう。

aws ec2 create-route                                  \
    --region $REGION                                  \
    --route-table-id $APPLICATION_SUBNET_ROUTE_TABLE  \
    --destination-cidr-block 10.0.0.0/24              \
    --network-interface-id $APPLIANCE_ENI_ID

Amazon VPC コンソールを使用してこれらの変更を加えることもできます。「踏み台」ルーティングテーブルを選択し、[ルート] タブから [ルートの編集] をクリックするだけです。MSR : ルーティングテーブルを選択

10.0.1.0/24(アプリケーションのサブネット)のトラフィックをアプライアンスENI(eni-055...))に送信するルートを追加します。MSR: ルートを作成

次のステップは、応答のため、反対ルートを定義することで、アプリケーションサブネットからトラフィックを 10.0.0.0/24、アプライアンス ENI(eni-05...)に送信します。 完了すると、アプリケーションサブネットルーティングテーブルは次のようになります:

MSR: 最終ルートテーブル

アプライアンスインスタンスの設定
最後に、受信したすべてのトラフィックを転送するようにアプライアンスインスタンスを設定します。通常、ソフトウェアアプライアンスがそれを行います。AWS Marketplace アプライアンス、またはこのデモ用に提供したCDK スクリプトによって作成されたインスタンスを使用する場合は、追加ステップは必要ありません。プレーンな Linux インスタンスを使用している場合は、次の 2 つの追加ステップを実行します。

1.EC2 アプライアンスインスタンスに接続し、カーネルで IP トラフィック転送を設定します。

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1

2.EC2 インスタンスが、そのインスタンス以外の宛先のトラフィックを受け入れるように設定します(送信元/送信先チェックと呼ばれます)。

APPLIANCE_ID=$(aws --region $REGION ec2 describe-instances                     \
     --filter "Name=tag:Name,Values=appliance"                                 \
     --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" \
     --output text)

aws ec2 modify-instance-attribute --region $REGION     \
                         --no-source-dest-check        \
                         --instance-id $APPLIANCE_ID

セットアップをテストする
これで、アプライアンスがトラフィックを他の EC2 インスタンスに転送する準備ができました。

デモ設定を使用している場合は、踏み台ホストに SSH キーがインストールされていません。アクセスはAWS Systems Manager セッションマネージャーを介して行われます。

BASTION_ID=$(aws --region $REGION ec2 describe-instances                      \
    --filter "Name=tag:Name,Values=BastionHost"                               \
    --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" \
    --output text)

aws --region $REGION ssm start-session --target $BASTION_ID

踏み台ホストに接続したら、次の cURL コマンドを作成してアプリケーションホストに接続します。

sh-4.2$ curl-I 10.0.1.239 # アプリケーションホストのプライベート IP アドレスを使用
HTTP/1.1 200 OK
サーバー:nginx/1.18.0
日時:2021年5月24日 (月) 10:00:22 GMT
Content-Type: text/html
Content-Length: 12338
最終更新:2021年5月24日 (月) 09:36:49 GMT
Connection: Keep-Alive
ETag: "60ab73b1-3032"
Accept-Ranges:バイト

トラフィックが実際にアプライアンスを通過していることを確認するには、インスタンスの送信元/送信先チェックを再度有効にします。上のmodify-instance-attribute CLI コマンドを使用して、 —source-dest-checkパラメータを使用します。送信元/送信先チェックが有効な場合、トラフィックはブロックされます。

アプライアンスホストに接続し、 tcpdump コマンドを使用してトラフィックを調べることもできます。

(ノートパソコンで)
APPLIANCE_ID=$(aws --region $REGION ec2 describe-instances     \
                   --filter "Name=tag:Name,Values=appliance" \
		   --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" \
  		   --output text)

aws --region $REGION ssm start-session --target $APPLIANCE_ID

(アプライアンス・ホスト上)
tcpdump-i eth0 ホスト 10.0.0.16 # 踏み台ホストのプライベート IP アドレス

08:53:22.760055 IP ip-10-0-0-16.us-west-2.compute.internal.46934 > ip-10-0-1-104.us-west-2.compute.internal.http: Flags [S], seq 1077227105, win 26883, options [mss 8961,sackOK,TS val 1954932042 ecr 0,nop,wscale 6], length 0
08:53:22.760073 IP ip-10-0-0-16.us-west-2.compute.internal.46934 > ip-10-0-1-104.us-west-2.compute.internal.http: Flags [S], seq 1077227105, win 26883, options [mss 8961,sackOK,TS val 1954932042 ecr 0,nop,wscale 6], length 0
08:53:22.760322 IP ip-10-0-1-104.us-west-2.compute.internal.http > ip-10-0-0-16.us-west-2.compute.internal.46934: Flags [S.], seq 4152624111, ack 1077227106, win 26847, options [mss 8961,sackOK,TS val 4094021737 ecr 1954932042,nop,wscale 6], length 0
08:53:22.760329 IP ip-10-0-1-104.us-west-2.compute.internal.http > ip-10-0-0-16.us-west-2.compute.internal.46934: Flags [S.], seq 4152624111, ack 1077227106, win 26847, options [mss 

クリーンアップ
この投稿で提供した CDK スクリプトを使用した場合は、完了したら cdk destroy を実行してください。こうすれば、このデモで使用する 3 つの EC2 インスタンスと NAT ゲートウェイの料金が請求されません。us-west-2 でデモスクリプトを実行すると、1 時間あたり 0.062 USD がかかります

留意すべき点。
VPC のより具体的なルートを使用する場合は、次の二点に留意します。

  • トラフィックの送信先のネットワークインターフェイスまたはサービスエンドポイントは、専用のサブネット内である必要があります。トラフィックの送信元または送信先サブネットには存在できません。
  • アプライアンスをチェーンできます。各アプライアンスは、専用のサブネット内に存在する必要があります。
  • 追加する各サブネットは、IP アドレスのブロックを消費します。 IPv4 を使用している場合は、消費される IP アドレスの数を意識してください(A/24 サブネットは VPC から 256 アドレスを消費します)。サブネットで許可される最小の CIDR 範囲は /28 で、IP アドレスを16消費するだけです。
  • アプライアンスのセキュリティグループには、目的のポートで着信トラフィックを受け入れるルールが必要です。同様に、アプリケーションのセキュリティグループは、アプライアンスのセキュリティグループまたは IP アドレスからのトラフィックを許可する必要があります。

この新しい機能は、すべての AWS リージョンで、追加コストがかからずに利用できます。

今すぐ使用できます。

原文はこちらです。