ネットワーク ACL の戻り経路を診断する

AWSBeginner
オンラインで実践に進む

はじめに

公開配送アプリにはインターネットルート、パブリックアドレス、HTTP を許可するセキュリティグループがありますが、クライアント A は読み取れません。サブネットのネットワーク ACL はリクエストの宛先ポートを許可し、クライアントへの戻りポートを遮断しています。この経路を診断・修復し、ルールの優先順位を観察した後、提供された初期設定へ戻します。

先に Connect Privately to S3 with a VPC Endpoint を完了してください。この新しい環境には独立したアプリ、パブリックとプライベートのサブネット、公開ルート、アドレス、グループ、カスタム ACL が用意され、CLI も設定済みです。これらと参照ネットワークを維持してください。本ラボの ACL ルールだけを変更し、後片付けで一時的な拒否を削除します。最終状態は意図的に初期障害を再現し、提供されたアプリを削除しません。

認定試験との関連

以下の試験分野に関する基礎練習です。

アプリのサブネット境界を調べる

変更する前にアプリを特定し、ルート、セキュリティグループ、ACL を比較します。

Terminal を使い、横に AWS View を開きます。公開アプリのプライベートアドレスは 10.20.1.10。クライアント A は 198.51.100.10、B は 198.51.100.20 です。提供されたグループは A の TCP 80 だけを許可し、8081 は許可していません。

cd /home/labex/project

Name タグで VPC を選択します。フィルターでリソースを選び、query で ID を抽出し、$(...) で保存します。

VPC_ID=$(aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=application-network \
  --query 'Vpcs[0].VpcId' \
  --output text)

パブリックサブネットと提供されたインターフェースを保存します。

SUBNET_ID=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=public-subnet \
  --query 'Subnets[0].SubnetId' \
  --output text)
ENI_ID=$(aws ec2 describe-network-interfaces \
  --filters "Name=subnet-id,Values=$SUBNET_ID" \
  --query 'NetworkInterfaces[0].NetworkInterfaceId' \
  --output text)

プライベートアドレス、パブリックアドレスの関連付け、接続されたグループを読み取ります。

aws ec2 describe-network-interfaces \
  --network-interface-ids "$ENI_ID" \
  --query 'NetworkInterfaces[].{Private:PrivateIpAddress,Public:Association.PublicIp,Groups:Groups}' \
  --output json

サブネットに関連付けられたテーブルを読み取ります。

aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=$SUBNET_ID" \
  --query 'RouteTables[].{Routes:Routes,Associations:Associations}' \
  --output json

パブリックアドレスは関連付け済みで、有効な 0.0.0.0/0 ルートがインターネットゲートウェイを指します。グループを保存して読み取ります。

GROUP_ID=$(aws ec2 describe-security-groups \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=group-name,Values=supplied-application \
  --query 'SecurityGroups[0].GroupId' \
  --output text)
aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].{Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
  --output json

受信は 198.51.100.10/32 からの TCP 80、送信は提供されたデフォルト許可です。これらを維持してください。

ネットワーク ACL はサブネット境界を通る通信を制御します。各サブネットには 1 つの ACL があり、1 つの ACL は複数サブネットに利用できます。ステートフルなグループと異なり ACL はステートレスで、リクエストを許可しても応答は自動許可されません。アプリのサブネットに関連付けられた ACL を選択します。

ACL_ID=$(aws ec2 describe-network-acls \
  --filters "Name=association.subnet-id,Values=$SUBNET_ID" \
  --query 'NetworkAcls[0].NetworkAclId' \
  --output text)

識別情報、関連付け、独立した受信・送信エントリを読み取ります。

aws ec2 describe-network-acls \
  --network-acl-ids "$ACL_ID" \
  --query 'NetworkAcls[].{ID:NetworkAclId,Default:IsDefault,Associations:Associations,Entries:Entries}' \
  --output json

これはデフォルトではなくカスタム application-acl です。ルール 100 は双方向で A の TCP 宛先 80 を許可します。Egress: false は受信、true は送信、プロトコル 6 は TCP です。不一致通信は最後の拒否に到達し、AWS View では *、CLI では 32767 と表示されます。

AWS View の Request application · client A をクリックします。ルートとグループ許可があっても Connection failed になります。Request application · client B と Request port 8081 も失敗します。保存した ID を維持するため、この Terminal を開いたままにします。

クライアント戻りポートのルールを修復する

クライアントの限定アドレスを維持したまま、誤った送信ポートを置き換えます。

HTTP リクエストはクライアントの選んだエフェメラルポートからサーバーの 80 へ、応答はサーバーの 80 からクライアントのそのポートへ進みます。ACL は各方向でパケットの宛先ポートを照合するため、送信宛先 80 の許可では応答を通せません。

エフェメラル範囲は接続を開始するクライアントによって異なります。本演習では一般的な範囲 1024–65535 を A 198.51.100.10/32 宛てだけに許可します。全 OS 共通のデフォルトではありません。既存の送信 100 を置き換えます。--egress は送信、--port-range は宛先範囲を指定します。

aws ec2 replace-network-acl-entry \
  --network-acl-id "$ACL_ID" \
  --rule-number 100 \
  --protocol 6 \
  --rule-action allow \
  --egress \
  --cidr-block 198.51.100.10/32 \
  --port-range From=1024,To=65535

成功時に出力はありません。エントリを読み取ります。

aws ec2 describe-network-acls \
  --network-acl-ids "$ACL_ID" \
  --query 'NetworkAcls[].Entries' \
  --output json

受信 100 は引き続き A の TCP 80 を許可します。送信 100 は同じクライアント宛ての 1024–65535 を許可します。デフォルト拒否とサブネット関連付けは変更しません。

AWS View で Request application · client A を再度クリックすると、新しいリクエストは Application online、送信元 198.51.100.10、宛先ポート 80 で成功します。Request application · client B と Request port 8081 は失敗したままです。受信グループや ACL を他のクライアントへ拡張せずに、リクエストと応答の両方が通るようになりました。

修復した ACL は A を許可しデフォルト拒否を維持する

例:受信 100 は A の TCP 80、送信 100 は A 宛ての応答宛先 1024–65535 を許可します。最後の拒否が双方向に表示され、実際のリクエストは Application online を返します。リソース ID は環境で異なります。

小さい番号の拒否ルールを観察する

順序の効果を見るため、受信許可より前に一致する拒否を意図的に追加します。

ACL は方向ごとに小さい番号から評価し、最初の一致で結果を決定します。後続ルールは評価されません。A の TCP 80 を拒否する一時的な受信 90 を追加します。--ingress は明示的な受信指定で、90 の作成は 100 を上書きしません。

aws ec2 create-network-acl-entry \
  --network-acl-id "$ACL_ID" \
  --rule-number 90 \
  --protocol 6 \
  --rule-action deny \
  --ingress \
  --cidr-block 198.51.100.10/32 \
  --port-range From=80,To=80

エントリを読み取ります。

aws ec2 describe-network-acls \
  --network-acl-ids "$ACL_ID" \
  --query 'NetworkAcls[].Entries' \
  --output json

受信拒否 90 は許可 100 より先に一致します。送信 100 は戻りポートを、グループは A の HTTP を許可したままですが、どちらも先の ACL 拒否を覆しません。

AWS View が受信 90 を表示したら Request application · client A をクリックします。新しいリクエストは失敗し、B と 8081 も遮断されたままです。以前の成功表示は履歴なので、変更後に再要求します。このステップのチェックまで 90 を残し、次で削除します。

一時的な拒否を削除してアクセスを再確認する

先の拒否だけを削除し、修復済みの戻り経路が動くことを確認します。

受信 90 を削除します。受信と送信では番号が独立しているため方向が重要です。

aws ec2 delete-network-acl-entry --network-acl-id "$ACL_ID" --rule-number 90 --ingress

再度エントリを読み取ります。

aws ec2 describe-network-acls \
  --network-acl-ids "$ACL_ID" \
  --query 'NetworkAcls[].Entries' \
  --output json

90 はありません。受信 100 は A の TCP 80、送信 100 は戻りポートを許可し、不一致通信は拒否します。元のサブネット関連付け、グループ、公開ルートとアドレスを維持します。

AWS View の新しい Request application · client A は Application online を返します。Request application · client B と Request port 8081 は失敗します。ステートフルなグループは許可した要求の応答を通しますが、ステートレス ACL は双方向の許可を必要とします。先の拒否を取り除くと、この独立した境界の通信が戻ります。

提供された ACL の初期設定に戻す

戻りポートの変更を取り消し、一時的な拒否が残っていないことを確認して、提供リソースを維持します。

送信 100 を提供された宛先 80 に戻します。この後片付けは意図的に初期障害を再現するもので、正常な HTTP 応答に推奨されるルールではありません。

aws ec2 replace-network-acl-entry \
  --network-acl-id "$ACL_ID" \
  --rule-number 100 \
  --protocol 6 \
  --rule-action allow \
  --egress \
  --cidr-block 198.51.100.10/32 \
  --port-range From=80,To=80

関連付けを含む VPC 全体の ACL 一覧を読み取ります。削除可能なタグだけを後片付けの証拠にしないでください。

aws ec2 describe-network-acls \
  --filters "Name=vpc-id,Values=$VPC_ID" \
  --query 'NetworkAcls[].{ID:NetworkAclId,Default:IsDefault,Associations:Associations,Entries:Entries}' \
  --output json

一時的な 90 は存在してはいけません。提供されたカスタム ACL は公開アプリサブネットに残ります。両方の 100 は A の TCP 宛先 80 を照合し、最後の拒否は維持されます。プライベートサブネットはデフォルト ACL を維持します。提供された ACL、サブネット、アプリ、グループ、ゲートウェイや公開アドレスを削除・置換しないでください。

元のグループを読み取り、ルールが維持されたことを確認します。

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].{Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
  --output json

AWS View の新しい Request application · client A は、戻りポートが許可されなくなったため再び失敗します。B と 8081 も遮断されたままです。API エラーやアプリネットワークの利用不能は後片付けの証拠ではありません。認証済み一覧取得は成功し、実際の設定経路が上記の結果を返す必要があります。

このステップの完了チェックを実行してください。

まとめ

アプリの ACL を特定し、不足した応答ポート範囲を診断しました。送信ルールを置き換えると A の実際の HTTP が復旧し、他の送信元とポートは遮断されたままでした。小さい番号の受信拒否で最初の一致による順序を確認し、削除するとアクセスが復旧しました。

グループ、ルート、アドレス、関連付けを維持し、一時的な拒否を削除して元の ACL 基準に戻しました。