AWS Client VPN に接続したら名前解決ができなくなったのでカスタム DNS サーバーとは何かを調べ直してみた

カスタム DNS サーバーを設定することで解決できることもあれば他のアプローチが必要な場合もあります。 DNS サーバへきちんと到達できることを意識しましょう。

コンバンハ、千葉(幸)です。

AWS Client VPN エンドポイントのパラメータの一つとして、カスタム DNS サーバー があります。明示的に設定しない限りはブランクである箇所なので、今まで特に気にせず過ごしてきました。

いろいろ設定を変えて検証する中で「名前解決できない!」という事態に陥り、ようやくその意味を調べることになりました。

今回はその内容についてまとめます。

ちなみに、私が引っかかったのは以下のようなケースです。

  • クライアントのデフォルトの DNS 参照先はインターネット上のサーバ
  • スプリットトンネル無効
    • (すべてのクライアントトラフィックが Clinet VPN 経由になる)
  • カスタム DNS サーバー未設定
  • ターゲットネットワークはプライベートサブネット

ここでは、ターゲットネットワークの ENI からインターネット上の DNS サーバに対して到達できず、 DNS ルックアップが失敗するという事象でした。(実はそれだけではなかったのですが、、)

解決策とあわせてご紹介します。

目次

先にまとめ

  • カスタム DNS サーバーを有効にすると、Client VPN 接続時に DNS パラメータがクライアントデバイスにプッシュされる
  • DNS サーバへの経路が確立されているかを、クライアントデバイスのルートテーブルを意識して考慮しよう
    • スプリットトンネル無効の場合デフォルトルートは Client VPN を向く
    • スプリットトンネル有効の場合は Clinet VPN ルートテーブルの内容がデバイスにプッシュされる
  • DNS サーバによっては接続元が制限されているので注意が必要

冒頭のケースについて補足

冒頭のケースの背景について、もう少し詳しく取りあげます。

なお、手元の環境は以下の通りです。

  • クライアントデバイス:macOS Catalina 10.15.7
  • VPN クライアント:AWS VPN Client 1.2.0

Client VPN 接続前

Client VPN に接続する前のクライアントデバイスの設定を確認します。 DNS サーバの参照先は以下の通りです。

  • 218.xxx.xxx.xxx
  • 220.xxx.xxx.xxx

macOS を使用しているため、/etc/resolv.confも確認しておきます。

% cat /etc/resolv.conf
#
# macOS Notice
#
# This file is not consulted for DNS hostname resolution, address
# resolution, or the DNS query routing mechanism used by most
# processes on this system.
#
# To view the DNS configuration used by this system, use:
#   scutil --dns
#
# SEE ALSO
#   dns-sd(1), scutil(8)
#
# This file is automatically generated.
#
domain xxx.xxx.xxx.ne.jp
nameserver 218.xxx.xxx.xxx
nameserver 220.xxx.xxx.xxx

名前解決を試みた際に、上記のサーバを参照していることが分かります。

 % dig dev.classmethod.jp +identify +short
52.69.244.142 from server 218.xxx.xxx.xxx in 20 ms.
13.114.112.43 from server 218.xxx.xxx.xxx in 20 ms.
52.196.7.133 from server 218.xxx.xxx.xxx in 20 ms.

Client VPN 接続時(スプリットトンネル無効)

続いて、以下設定の Client VPN に接続します。

  • スプリットトンネル無効
  • カスタム DNS サーバー未設定
  • ターゲットネットワークはプライベートサブネット
    • インターネットへの経路を持たない

接続したことにより、クライアントデバイスのルートテーブルに変更が加わります。

% netstat -rn
Routing tables

Internet:
Destination        Gateway            Flags        Netif Expire
0/1                172.16.0.129       UGSc         utun2
default            192.168.0.1        UGSc           en0
18.177.246.62/32   192.168.0.1        UGSc           en0
127                127.0.0.1          UCS            lo0
127.0.0.1          127.0.0.1          UH             lo0
128.0/1            172.16.0.129       UGSc         utun2
169.254            link#6             UCS            en0      !
169.254.150.178    d4:6a:6a:5f:32:e7  UHLSW          en0      !
172.16.0.128/27    172.16.0.130       UGSc         utun2
172.16.0.130       172.16.0.130       UH           utun2
192.168.0          link#6             UCS            en0      !
192.168.0.1/32     link#6             UCS            en0      !
192.168.0.1        90:f3:5:ee:a2:bb   UHLWIir        en0   1136
192.168.0.14/32    link#6             UCS            en0      !
224.0.0/4          link#6             UmCS           en0      !
224.0.0.251        1:0:5e:0:0:fb      UHmLWI         en0
239.255.255.250    1:0:5e:7f:ff:fa    UHmLWI         en0
255.255.255.255/32 link#6             UCS            en0      !

デフォルトルートが上書き( 0/1 および 128.0/1 宛ルートが追加)され、すべてのクライアントトラフィックが Client VPN トンネルを経由することになります。

このあたりの挙動は以下エントリでも取りあげましたのであわせてご参照ください。

一方で、参照先の DNS サーバには変更がありません。

% cat /etc/resolv.conf | grep nameserver
nameserver 218.xxx.xxx.xxx
nameserver 220.xxx.xxx.xxx

そのため、名前解決を試みると、デフォルトの DNS サーバを参照しに行きます。DNS ルックアップの通信は Client VPN エンドポイントを経由し、ターゲットネットワーク の ENI から宛先のサーバを目指しますが、今回のケースではインターネットに通信可能な状態でないため、名前解決に失敗します。

% dig dev.classmethod.jp +identify +short

; <<>> DiG 9.10.6 <<>> dev.classmethod.jp +identify +short
;; global options: +cmd
;; connection timed out; no servers could be reached

(なお、参照先として Amazon Provided DNS こと Route53 Resolver を明示的に指定すれば、問題なく名前解決はできます。)

% dig @10.0.0.2 dev.classmethod.jp +identify +short
52.196.7.133 from server 10.0.0.2 in 23 ms.
52.69.244.142 from server 10.0.0.2 in 23 ms.
13.114.112.43 from server 10.0.0.2 in 23 ms.

どう対応すればいいのか

今回のケースにおいて、問題なく名前解決が行えるようにするためにはどのように構成を変更すればよいでしょうか。

以下の 3 パターンで考えてみます。

  1. カスタム DNS サーバーを使用する
  2. ターゲットネットワークからインターネット疎通を可能にする
  3. スプリットトンネルを有効化する

パターン1. カスタム DNS サーバーを使用する

本エントリのメインテーマであるカスタム DNS サーバーを使用します。以下観点で、最も改修のインパクトが少なく済むパターンかと思います。

  • VPC の構成を変更しない
    • (パターン2. ではここが変わる)
  • インターネット向けの経路を変更しない
    • (パターン3. ではここが変わる)

カスタム DNS サーバーとして設定した値は、 VPN 接続時にクライアントにプッシュされます。先ほど手動で指定した Amazon Provided DNS を自動的に参照するように設定します。

Client VPN エンドポイントの変更画面より設定を行います。[ DNS サーバーを有効にする ] にチェックを入れ、指定する DNS サーバーの IP アドレスを入力します。

Amazon Provided DNS の IP アドレスは、VPC IPv4 ネットワークの範囲に 2 をプラスしたものです。

上記の変更が完了したのちに Client VPN に接続すると、参照先 DNS サーバが変更されていることが分かります。(本エントリでいちばん書きたかったところは実はここ)

% cat /etc/resolv.conf
#
# macOS Notice
#
# This file is not consulted for DNS hostname resolution, address
# resolution, or the DNS query routing mechanism used by most
# processes on this system.
#
# To view the DNS configuration used by this system, use:
#   scutil --dns
#
# SEE ALSO
#   dns-sd(1), scutil(8)
#
# This file is automatically generated.
#
search openvpn
nameserver 10.0.0.2

名前解決を試みると、Amazon Provided DNS を参照して問題なく IP アドレスを引けました。

% dig dev.classmethod.jp +identify +short
13.114.112.43 from server 10.0.0.2 in 32 ms.
52.196.7.133 from server 10.0.0.2 in 32 ms.
52.69.244.142 from server 10.0.0.2 in 32 ms.

Amazon Provided DNS を参照先としている場合、VPC に関連づけられた Route 53 プライベートホストゾーンのレコードも引けます。

なお、当然ですが Client VPN との接続を切断すると参照先 DNS サーバーは元に戻ります。

パターン2. ターゲットネットワークからインターネット疎通を可能にする

カスタム DNS サーバーを使用せず、デフォルトの DNS 参照先に対しての通信経路を確保することで対応するパターンです。

結果から言うと、このパターンは失敗しました。私の環境では、もともと参照していた DNS サーバーが(おそらく)接続元を制限していたためです。

やろうとしたことは以下です。ターゲットネットワークの ENI から、インターネット上の DNS サーバにアクセス可能なように設定すれば問題なく名前解決できるだろうと考えていました。

結果的にダメだったですが、試行したことを載せておきます。

ターゲットネットワークで NAT Gateway 向けのルートを追加するか、パブリックサブネットに変更することでインターネットに出ていけるようになります。今回は NAT Gateway パターンで構成しました。

エンドポイントを以下条件に設定し直して、Client VPN に接続しました。

  • カスタム DNS サーバー指定なし
  • スプリットトンネル無効

カスタム DNS サーバーは設定していないため、参照先はデフォルトのままです。

% cat /etc/resolv.conf | grep nameserver
nameserver 218.xxx.xxx.xxx
nameserver 220.xxx.xxx.xxx

ここで名前解決を試みると、タイムアウトしてしまいます。

% dig dev.classmethod.jp +identify +short

; <<>> DiG 9.10.6 <<>> dev.classmethod.jp +identify +short
;; global options: +cmd
;; connection timed out; no servers could be reached

DNS サーバーへ到達できるかを確認します。 Ping による疎通確認は Client VPN 接続前の環境でも拒否されていたため、nc による確認を行いました。

Client VPN 接続前は以下のように接続が成功します。

% nc -v  218.xxx.xxx.xxx 53 -u
Connection to 218.xxx.xxx.xxx port 53 [udp/domain] succeeded!
% nc -v  218.xxx.xxx.xxx 53
Connection to 218.xxx.xxx.xxx port 53 [tcp/domain] succeeded!

Client VPN に接続した後に同様のコマンドを実行すると、レスポンスが無いという結果になりました。そのため、通信が拒否されているのだと捉えました。

パブリック DNS である 8.8.8.8 や 1.1.1.1 を指定したところ問題なく名前解決ができます。インターネット上のリソースだから NG というわけではありません。

% dig @8.8.8.8 dev.classmethod.jp +identify +short
52.69.244.142 from server 8.8.8.8 in 25 ms.
13.114.112.43 from server 8.8.8.8 in 25 ms.
52.196.7.133 from server 8.8.8.8 in 25 ms.
% dig @1.1.1.1 dev.classmethod.jp +identify +short
52.69.244.142 from server 1.1.1.1 in 29 ms.
13.114.112.43 from server 1.1.1.1 in 29 ms.
52.196.7.133 from server 1.1.1.1 in 29 ms.

今回の環境でもともと参照していたのはプロバイダから提供された DNS サーバでした。DNS サーバによっては、リゾルバとしての接続を許可する送信元を限定しているでのはないか、と捉えています。

デフォルトの参照先を 8.8.8.8 や 1.1.1.1 に設定している環境であれば、このパターンで問題なく成功します。

パターン3. スプリットトンネルを有効化する

最後のパターンです。スプリットトンネルを有効化することで、VPN トンネルを経由せずに従来の DNS サーバ宛に通信が可能になります。

なお、DNS 宛の通信に限らず、インターネット向けの通信すべてが VPN トンネルを経由しなくなることに注意してください。この例では Client VPN ルートテーブルに 0.0.0.0/0 宛のルートが定義されていますが、そのルートはクライアントデバイスにプッシュされません。

Client VPN エンドポイントでスプリットトンネルを有効化し接続すると、クライアントデバイスのルートテーブルは以下のようになりました。変更が加わったのはハイライト部で、デフォルトルートは従来の物のままです。

% netstat -rn
Routing tables

Internet:
Destination        Gateway            Flags        Netif Expire
default            192.168.0.1        UGSc           en0
10/16              172.16.0.1         UGSc         utun2
127                127.0.0.1          UCS            lo0
127.0.0.1          127.0.0.1          UH             lo0
169.254            link#6             UCS            en0      !
169.254.150.178    d4:6a:6a:5f:32:e7  UHLSW          en0      !
172.16/27          172.16.0.2         UGSc         utun2
172.16.0.2         172.16.0.2         UH           utun2
192.168.0          link#6             UCS            en0      !
192.168.0.1/32     link#6             UCS            en0      !
192.168.0.1        90:f3:5:ee:a2:bb   UHLWIir        en0   1145
192.168.0.14/32    link#6             UCS            en0      !
224.0.0/4          link#6             UmCS           en0      !
224.0.0.251        1:0:5e:0:0:fb      UHmLWI         en0
239.255.255.250    1:0:5e:7f:ff:fa    UHmLWI         en0
255.255.255.255/32 link#6             UCS            en0      !

カスタム DNS サーバーを指定していないため、参照先は変わりません。

% cat /etc/resolv.conf | grep nameserver
nameserver 218.xxx.xxx.xxx
nameserver 220.xxx.xxx.xxx

もちろん名前解決は成功します。

% dig dev.classmethod.jp +identify +short
13.114.112.43 from server 218.xxx.xxx.xxx in 30 ms.
52.69.244.142 from server 218.xxx.xxx.xxx in 30 ms.
52.196.7.133 from server 218.xxx.xxx.xxx in 30 ms.

インターネットに接続する IP を確認すると、リモート環境で使用している物が返却されます。

% curl checkip.amazonaws.com/
202.xx.xx.xxx

Client VPN 接続時にもクライアントデバイスから直接( VPN を経由せず)インターネットに通信してよい、というポリシーの環境であれば、スプリットトンネルを有効化したほうがシンプルに済みます。

終わりに

AWS Client VPN における名前解決およびカスタム DNS サーバーについてでした。

Client VPN 接続時にはカスタム DNS サーバーとして指定した IP がクライアントデバイスにプッシュされる。そのため、クライアントデバイスから DNS サーバーに対してきちんと疎通できる状態を意識する必要がある、ということを学びました。

実はパターン2. も成功する気マンマンでブログを書き始めていたので、やってみないとわからないことだらけだなぁというのを再認識しました。

以上、千葉(幸)がお送りしました。