🌍

Route53 IPベースルーティングでハマった(DNSリゾルバ依存&IPv6)

に公開

12/15: IPv6に関して追記

はじめに

Route53のIPベースルーティングを使って社内VPNユーザーと一般ユーザーでの環境振り分けを実装しようとして、落とし穴にハマった。設定は正しいはずなのに、ルーティングが期待通りに動作しない...

最終的に、ECS(EDNS Client Subnet)をサポートしているDNSリゾルバでないと、IPベースルーティングは正常に機能しないということだった。

やりたかったこと

本番環境で以下のような振り分けを実現したかった:

[社内VPNユーザー] → [Route53 IPベースルーティング] → [ステージング環境]
[一般ユーザー]   → [Route53 IPベースルーティング] → [本番環境]

ユースケース

  • UATテストのため、社内VPNからのアクセスだけステージング環境に流したい
  • 一般ユーザーには本番環境を提供する
  • 同じドメイン(api.example.com)で透明に振り分けたい

設定内容

Route53でIPベースのルーティングポリシーを設定:

{
  "Type": "CNAME",
  "Name": "api.example.com",
  "SetIdentifier": "Internal-VPN",
  "RoutingPolicy": {
    "Type": "IPBased",
    "IPAddressRanges": ["192.168.1.0/24"]  // 社内VPN IP範囲
  },
  "TTL": 300,
  "ResourceRecords": ["staging-alb-123456789.ap-northeast-1.elb.amazonaws.com"]
}
{
  "Type": "CNAME", 
  "Name": "api.example.com",
  "SetIdentifier": "Public",
  "RoutingPolicy": {
    "Type": "IPBased",
    "IsDefault": true  // デフォルトルート(一般ユーザー用)
  },
  "TTL": 300,
  "ResourceRecords": ["prod-alb-987654321.ap-northeast-1.elb.amazonaws.com"]
}

問題:ルーティングが機能しない

設定完了後、テストしてみると...

  • 社内VPNからアクセスしても本番環境のALBに飛ぶ
  • IPベースの振り分けが全く機能していない

期待: 社内VPN → ステージング環境のALB
現実: 社内VPN → 本番環境のALB(デフォルトルート)

原因:DNSリゾルバのECS対応が必要

AWSの記事に以下の記載がある。

When a Route 53 DNS server receives a query from a DNS resolver, the source IP address of the resolver is always present. In addition Route 53 supports the Extension Mechanisms for DNS (EDNS; RFC 6891), which allows DNS resolvers that implement EDNS Client Subnet (RFC 7871) to also include the IP range of the original client that made the query. When present, this allows Route 53 to more accurately determine the client’s location.

When it is available, Route 53 will use the ECS value to determine responses for the client. Otherwise, it will use the resolver’s IP.

ECSとは

ECSは、DNSリゾルバがDNSクエリに実際のクライアントのIPアドレス情報を含めて送信する仕組み。

[クライアント] → [ECS対応DNSリゾルバ] → [Route53]
              クライアントIP情報を含む

ECS非対応の場合:

[クライアント] → [非対応DNSリゾルバ] → [Route53]
              リゾルバのIPしか分からない

事象再現

VPNへ接続。

# 1.1.1.1を指定しリクエスト(期待していない返り値(デフォルト値))
% nslookup api.example.com 1.1.1.1
Server:		1.1.1.1
Address:	1.1.1.1#53

Non-authoritative answer:
api.example.com	canonical name = prod-alb-987654321.ap-northeast-1.elb.amazonaws.com.

# 8.8.8.8を指定しリクエスト(期待した返り値)
% nslookup api.example.com 8.8.8.8
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
api.example.com	canonical name = staging-alb-123456789.ap-northeast-1.elb.amazonaws.com.

解決方法a

利用するPCのDNSリゾルバを対応しているリゾルバに変更する。

1. 利用するPCのDNSリゾルバを確認

Macの場合

~ % scutil --dns
...
DNS configuration (for scoped queries)

resolver #1
  search domain[0] : openvpn
  nameserver[0] : x.x.x.x
  nameserver[1] : y.y.y.y
...
# または
~ % cat /etc/resolv.conf
...
nameserver x.x.x.x
nameserver y.y.y.y

2. DNSリゾルバがECSをサポートしているか確認

サポートしている場合、edns0-client-subnet 49.129.42.0/24のような値が返される。

% dig +nocl TXT o-o.myaddr.l.google.com @8.8.8.8 +short
"edns0-client-subnet 49.129.42.0/24"
"172.253.236.156"
% dig +nocl TXT o-o.myaddr.l.google.com @1.1.1.1 +short
"172.70.232.8"
% dig +nocl TXT o-o.myaddr.l.google.com @1.0.0.1 +short
"2400:cb00:455:1024::ac46:e808"
% dig +nocl TXT o-o.myaddr.l.google.com @9.9.9.9 +short
"74.63.20.236"

3. 変更方法

Macの場合

# ネットワークサービス一覧表示
% networksetup -listallnetworkservices
An asterisk (*) denotes that a network service is disabled.
Wi-Fi
xxx
yyy
zzz
# 利用しているのがWi-Fiの場合
~ % sudo networksetup -setdnsservers "Wi-Fi" 8.8.8.8 8.8.4.4\n

または、システム設定>Wi-Fi>接続中のWi-Fiの詳細>DNS>DNSサーバから登録

解決方法b(IPv6が有効な環境の場合)

上記の解決方法aでも解決しない場合、IPv6が原因の可能性がある。

問題

macOSなどでIPv6が有効な場合、DNSクエリがIPv6 + DNS over HTTPS(DoH)経由で送信され、VPNトンネルを経由しないことがある。

この場合、ECS対応のDNSリゾルバ(8.8.8.8)を設定していても、IPv6経由のDNSクエリにはクライアントIPが正しく通知されず、IPベースルーティングが機能しない。

確認方法

1. IPv6のルーティングを確認

netstat -rn -f inet6 | grep default

結果にen0(Wi-Fi)などVPN以外のインターフェースがある場合、IPv6トラフィックはVPNを経由していない。

default                                 fe80::xxxx:xxxx:xxxx:xxxx%en0            UGcg                  en0  ← VPNを経由していない
default                                 fe80::%utun0                            UGcIg               utun0

2. DNS over HTTPSの接続を確認

sudo lsof -i | grep -i dns

以下のようにIPv6でdns.googleへのHTTPS接続がある場合、DoH経由でDNSクエリが送信されている。

mDNSRespo ... TCP [2404:7a84:...]:51262->dns.google:https (ESTABLISHED)

解決方法

Macの場合

VPN接続前にIPv6を無効化する。

sudo networksetup -setv6off Wi-Fi

その後、DNSキャッシュをクリアして確認。

sudo killall -9 mDNSResponder
sleep 2
nslookup api.example.com

VPN切断後、IPv6を元に戻す場合は以下を実行。

sudo networksetup -setv6automatic Wi-Fi

根本的な解決策

AWS Client VPNは2025年8月からIPv6およびDual-stack(IPv4/IPv6両対応)をサポートしている。

Client VPNエンドポイントをDual-stackに設定することで、IPv6トラフィックもVPNトンネル経由となり、クライアント側でIPv6を無効にする必要がなくなる。

詳細はAWS公式ドキュメントを参照。

動作確認

VPNへ接続。

CLI上での確認

# DNSサーバ指定せずにリクエストする(期待値が返ってくる)
% nslookup api.example.com
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
api.example.com	canonical name = staging-alb-123456789.ap-northeast-1.elb.amazonaws.com.

ブラウザによる確認

chrome://net-internals/#dns で、api.example.comをリクエストする。
nslookupで返された期待したIPアドレスを返しているか確認。

返り値が変わらない場合

キャッシュが残っている可能性があるため、キャッシュを削除する。

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

Discussion