【実務・中級編】 DNS名前解決リクエスト(Route 53 Resolver / AmazonProvidedDNS)におけるプライベートサブネットのルーティング – クラウド&コンテナネットワーク実践ガイド

プライベートサブネットの「見えざる壁」:DNS名前解決の深淵と実務的トラブルシューティング

こんにちは。現場で泥をすすりながらパケットの行方を追っているSREです。

AWSのインフラ設計において、パブリックサブネットとプライベートサブネットを分けるのは基本中の基本。しかし、いざ「プライベートサブネット上のインスタンスからインターネット上のAPIを叩く」といった構成を組んだ際、なぜか接続エラーでハマる。その原因の多くが「DNS名前解決」のメカニズムを理解していないことにあります。

今回は、VPC内のDNSリゾルバーである AmazonProvidedDNS と、プライベートサブネットのルーティングが織りなす「見えざる通信」について、現場の知見を交えて紐解いていきましょう。

—

1. AmazonProvidedDNSの正体と「魔法のIP」

まず、VPC内にあるインスタンスが google.com などのドメインを解決しようとするとき、どこに問い合わせているかご存知でしょうか?

VPCのCIDRブロックが 10.0.0.0/16 だとすると、DNSリゾルバーは 10.0.0.2 に配置されています。これがAWSの提供する AmazonProvidedDNS です。

なぜプライベートサブネットでも解決できるのか?

ここが初心者の躓きポイントです。プライベートサブネットにはインターネットゲートウェイ(IGW)へのルートがありませんよね。それなのに、なぜ外部のドメインを解決できるのか。

答えはシンプルで、「VPC内のDNSリゾルバー(10.0.0.2)自体が、AWSのバックボーンネットワーク経由で外部の権威DNSサーバーへ再帰的に問い合わせを行っているから」です。

つまり、インスタンスから 10.0.0.2 への通信は、ルーティングテーブルに 0.0.0.0/0 があろうとなかろうと、AWSのネットワーク基盤がよしなに処理してくれます。ここはプライベートサブネットであっても、「DNSクエリだけは特別扱い」される聖域なのです。

—

2. 実務で遭遇する「通信の断絶」とNATゲートウェイ

名前解決はできても、その後の「実際のパケット通信」でコケるのが典型的なパターンです。

  • DNS解決: インスタンス → (10.0.0.2) → インターネット上のDNSサーバー(成功)
  • API通信: インスタンス → (NATゲートウェイ) → インターネット上のAPIサーバー(ここが遮断される)

プライベートサブネット上のインスタンスにはパブリックIPが存在しません。そのため、インターネット上の外部APIにアクセスするには、NATゲートウェイが必須となります。もしNATゲートウェイの設定を忘れていれば、名前解決はできるのに curl や Fetch API がタイムアウトで落ちるという、一見不可解な現象に悩まされることになります。

デバッグのためのCLIコマンド例

まずは、名前解決ができているか、通信ができているかを切り分けましょう。

# 1. DNS解決ができるか確認(名前解決の疎通確認)
dig google.com @10.0.0.2

# 2. 実際のHTTP通信が通るか確認(パケットの疎通確認)
# -v オプションで詳細なハンドシェイクの過程を見るのがコツです
curl -v https://api.github.com

—

3. Pythonでの実装:タイムアウト設定の重要性

アプリケーション層で外部APIを叩く際、ネットワークの遅延やリゾルバーの不調を考慮した実装が必要です。特に requests ライブラリなどを使う場合、タイムアウトをデフォルトのままにしておくと、ネットワークトラブル時にスレッドがスタックし、システム全体が共倒れします。

import requests

def fetch_api_data(url):
    try:
        # ネットワークの不安定さを考慮し、タイムアウトを明示的に設定する
        # connect: 接続確立までの時間, read: データ受信までの時間
        response = requests.get(url, timeout=(3.05, 10))
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        # ここでログをしっかり吐くのがSREの流儀。
        # DNSエラーか、ルートがないためのタイムアウトかを切り分ける
        print(f"Network error occurred: {e}")
        return None

# 実行例
data = fetch_api_data("https://api.example.com/data")

—

4. 現場のシニアエンジニアからのTips:トラブルシューティングの心得

もしあなたがプライベートサブネットでネットワーク障害に遭遇したら、以下の手順で「切り分け」を行ってください。

1. Security Group (SG) の確認:
NATゲートウェイに向かうアウトバウンドの TCP/443 が許可されているか?意外とここが抜けています。
2. Network ACL (NACL) の確認:
サブネットレベルのNACLで、エフェメラルポート(1024-65535)のインバウンド通信を許可していますか?NACLはステートレスなので、リクエストだけでなくレスポンスの戻りポートも考慮が必要です。
3. VPCエンドポイントの確認:
S3やDynamoDBへの通信なら、NATゲートウェイを通す必要はありません。「ゲートウェイ型VPCエンドポイント」を使えばコストも抑えられ、ルーティングもシンプルになります。

最後に

「プライベートサブネットだから外部と繋がらない」と決めつけるのではなく、「DNSは特別枠で解決できるが、データプレーンの通信には出口(ゲートウェイ)が必要」という構造をパケットレベルでイメージしてください。

ネットワークは魔法ではありません。すべてはルーティングテーブルとステートフルなファイアウォールの挙動に支配されています。次に障害が起きたとき、慌ててコードをいじる前に、まず traceroute や tcpdump で「パケットがどこで死んでいるか」を特定する冷静さを持ってくださいね。

それが、一人前のクラウドエンジニアへの第一歩です。

コメント

タイトルとURLをコピーしました