AWS Client VPN のエンドポイントには接続でき、プライベートサブネットは応答するのに、公開ページはすべてタイムアウトします。この組み合わせは、管理側の三つの対象のどれかに問題を絞り込みます。クライアントが入れるルート、エンドポイントのルートとその承認ルール、または関連付けられたサブネットの次のホップです。クライアント側から見た症状がそれぞれ違うため、この順に確認します。本手順は VPC に関連付けたマネージドエンドポイントを対象とし、EC2 インスタンス上の OpenVPN サーバーや Cloud WAN / Transit Gateway の接続は対象外です。

まずクライアントが実際に何をルーティングしているかを確認する

接続済みという状態が証明するのは TLS セッションとクライアントへの CIDR 割り当てだけで、それ以上ではありません。トンネルが上がっている間に公開アドレスがどこへ向かうかを OS に尋ねます。Linux では ip route get 1.1.1.1 がトンネルインターフェースを示すはずです。macOS では netstat -rn -f inet | head -5 が既定のエントリを示し、Windows では Find-NetRoute -RemoteIPAddress 1.1.1.1 が選ばれたインターフェースと次のホップを出力します。

次に分割トンネルのフラグを読みます。エンドポイントが公開するルートだけがクライアントのトンネル宛ての宛先になるかどうかを、このフラグが決めるからです。

aws ec2 describe-client-vpn-endpoints \
  --client-vpn-endpoint-ids cvpn-endpoint-0123456789abcdef0 \
  --query 'ClientVpnEndpoints[0].SplitTunnel'

SplitTunnel が true の場合、公開宛先がトンネルを使うのは、それを覆うルートをエンドポイントが公開しているときに限られます。したがって 0.0.0.0/0 が欠けていると、その通信はローカルインターフェースに残ります。false の場合はクライアントが通信を捕捉しますが、エンドポイント側でルーティングと承認がなお必要で、そうでなければパケットはトンネルに入って止まります。どちらの設定を変えた後もクライアントを再接続してください。ルートと DNS サーバーは接続時に配布されるため、起動中のクライアントは古い一式を保持することがあります。

エンドポイントのルートと承認ルールを別々に読む

これは二つの対象で、片方を作ってももう片方はできません。エンドポイントのルートを一覧し、ターゲットが関連付けられたサブネットである既定ルートを探します。

aws ec2 describe-client-vpn-routes \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0

各ルートのターゲットサブネットはちょうど一つなので、三つの関連付けにはそれぞれ対応する既定ルートが必要です。AWS はこの網羅要件を文書化しており、欠けがあるときの実際の症状は、あるサブネットからは作業でき別のサブネットからは止まるという形で、ルートの欠落ではなく断続的な障害に見えます。公式の Client VPN のシナリオ文書 が、これらのルートが属するパブリックサブネットの構成を説明しています。

承認が二つ目の対象です。公開宛先を覆うルールがない場合、トンネルはパケットを運びますがサービスがそれを破棄するため、プライベートリソースは動き続け、インターネットだけが使えません。

aws ec2 describe-client-vpn-authorization-rules \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0

VPC の CIDR に対するルールは 0.0.0.0/0 について何も語りません。完全なトンネルに必要な欠けを補うには、関連付けられたサブネットごとに一つのルートと、後から監査できる承認ルールが一つ必要です。

aws ec2 create-client-vpn-route \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --target-vpc-subnet-id subnet-0a1b2c3d4e5f67890
aws ec2 create-client-vpn-authorization-rule \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --access-all \
  --description "internet egress for full tunnel"

--access-all はエンドポイントのすべてのクライアントに宛先を与えるので、トンネルを完全にする間だけ有効にしてください。結び付けられるグループがあるなら、ディレクトリグループに紐づけたルールのほうが望ましいです。

パケットが関連付けられたサブネットから出るところまで追う

エンドポイントのルートは、AWS がそのパケットをそのサブネットに渡すことを決めます。その先の次のホップは決めず、それはサブネット自身の VPC ルートテーブルにあります。

aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=subnet-0a1b2c3d4e5f67890 \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'

使える既定ルートは、パブリックサブネットならインターネットゲートウェイを、プライベートなら NAT ゲートウェイを指します。状態が blackhole であればターゲットが削除され、経路は静かに死んでいます。これはエンドポイントのルート一覧とは別のテーブルで、片方を直してももう片方は直りません。

このホップには二つのフィルターがあります。ターゲットのネットワーク関連付けに適用されたセキュリティグループが公開宛先への外向き通信を許可し、該当するネットワーク ACL が要求とエフェメラルポートの戻り通信を許可している必要があります。関連付けのセキュリティグループが制限的であることは、プライベートアクセスは通るのに公開アクセスが通らないよくある原因です。

三つを同時に変えるのではなく、症状から最初の層を選びます。

What you observeLayer to check first
No tunnel interface for a public IPClient route or split-tunnel flag
Tunnel interface chosen, request times outEndpoint route and authorization rule
Endpoint route present, still times outSubnet route table, association security group
Named host fails, numeric address worksDNS servers and their own authorization

DNS の失敗と死んだルートを切り分ける

名前解決の失敗は転送の失敗とは違い、完全なトンネルではこの違いが重要になります。押し出されたリゾルバーへはトンネル経由で到達するようになったからです。エンドポイントが VPC の DNS サーバーを指定している場合、そのアドレスにも他の宛先と同じくルートの網羅と承認が必要です。どちらの失敗かを知るには、リゾルバーへ直接問い合わせます。dig +short example.com @10.0.0.2、または nslookup example.com 10.0.0.2 を Windows で使います。

数値の URL が応答し、名前の URL が応答しない場合は、既定ルートの編集をやめて DNS に取り組みます。IP アドレスへの要求は、名前付きのバーチャルホストとその証明書について何も証明しないため、最終確認には名前付きの試験を一つ残してください。

時間も手がかりになります。数秒以内に応答がない TCP 接続はルーティングかフィルターを示し、名前解決の中で止まる要求はリゾルバーを示します。リゾルバーに到達できない状態で既定ルートを変えると、一つの障害が二つになりがちです。

きれいに元へ戻し、そのうえで出口の経路を確認する

どちらの対象も追加型なので、切り戻しは修復ではなく削除です。

aws ec2 delete-client-vpn-route \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --target-vpc-subnet-id subnet-0a1b2c3d4e5f67890
aws ec2 delete-client-vpn-authorization-rule \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --access-all

再接続し、通信がどの経路で出ているかを確認します。観測した公開アドレスを NAT ゲートウェイの弾性 IP アドレス、または使うつもりだったインターネットゲートウェイと比べ、同じセッションでプライベートリソースがまだ応答するかも確かめます。

短い一覧で締め、最後の項目は文書ではなく変更の一部として扱います。

  • 関連付けられたサブネットごとに 0.0.0.0/0 のエンドポイントルートを一つ。
  • サービス対象のクライアントに対して 0.0.0.0/0 を覆う承認ルールを一つ。
  • 関連付けられた各サブネットに blackhole でない VPC の既定ルート。
  • 関連付けのセキュリティグループの外向き通信と、ACL の戻り通信。
  • リゾルバーのアドレスをルーティングし承認したうえで、名前付きの要求で確認。
  • ルートとルールの切り戻し手順を記録。

範囲について一言。これは IPv4 の経路です。デュアルスタックのクライアントは既にある IPv6 接続をそのまま保つので、IPv6 の既定ルートはこれの副作用ではなく、独自の承認を伴う別の判断です。

関連記事