「やだ、、、DNS、、、怖い・・・」

自分は今までDNS全般についてずーっと苦手意識が強かったんですが、弊社大瀧が、DNSの社内勉強会を開催したのをきっかけに、今一度、digコマンドとRoute 53を利用しながらDNSの基礎について学んでみたので、その過程をご報告します。

digコマンドは、DNSの動作を確認する時のデファクトスタンダードと言えるコマンドですが、残念ながらWindowsには標準実装されていません。が、今回はEC2を利用しているので、Windowsな方も大丈夫です。

この記事を読めば、digコマンドの基本的な使い方と、DNSの挙動の基本的なところが把握できるかと思います。

目次は、こんな感じ。

検証用の環境を構築 digコマンドの基本的な利用方法を学ぶ EC2でdigコマンドをあれこれ試してみる Route 53のプライベートホストゾーンを作成し、DNSレコードを編集してみる

ほな、気軽にいってみましょ。

__ （祭） ∧ ∧ Y ( ﾟДﾟ) Φ[_ｿ__ｙ_l〉 DNSﾀﾞﾜｯｼｮｲ |_|＿| し'´Ｊ

検証用の環境を構築

以下の構成を作成します。フツーのVPCとEC2です。

作成手順の詳細は省略します。下記公式ドキュメントなどをご参照ください。

ざっくりとした手順はこちら。

VPC（dns-test-vpc）を作成する VPCのDNS解決とDNSホスト名をTrueに設定する（重要） インターネットゲートウェイを作成し、VPC(dns-test-vpc)に割り当てる サブネット（subnet01）を作成する サブネット（subnet01）に割り当ててるルーティングテーブルに、「送信先:0.0.0.0/0」にインターネットゲートウェイを割り当てる EC2インスタンス、app01、app02を作成する

Route 53のプライベートホストゾーンの作成が必要ですが、そこは後ほど説明します。

これから記載する全てのコマンドは、VPC内のEC2から実行していますのでご注意ください。

digコマンドの基本的な利用方法を学ぶ

これからdigコマンドを利用して、DNSの挙動を確認していくわけですが、最初にdigコマンドの利用方法を確認します。

digコマンドの基本使用例

$dig @DNSサーバー example.com クエリタイプ

オプション名 必須（？） 解説 @DNSサーバー 任意 名前解決に利用するDNSサーバーを指定 example.com 必須 対象ドメイン名 クエリタイプ 任意 問い合わせるDNSのリソースレコードタイプを指定

クエリタイプに指定できるタイプの一覧（一部）

リソースレコードタイプ 役割 A ホストのアドレス CNAME ホストの別名 MX ドメインのメール交換ホスト NS ドメインのネームサーバ TXT テキスト ANY 全てのタイプの全てのレコードを返す

試しに、digコマンドを利用して、yahoo.co.jpに名前解決してみましょう。

$ dig yahoo.co.jp ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> yahoo.co.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57517 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;yahoo.co.jp. IN A ;; ANSWER SECTION: yahoo.co.jp. 60 IN A 182.22.59.229 yahoo.co.jp. 60 IN A 183.79.135.206 ;; Query time: 5 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Fri Feb 2 23:53:47 2018 ;; MSG SIZE rcvd: 61

なんや、わらわら出力されましたが、以降で各セクションの内容を解説していきます。

digコマンド結果の確認方法

HEADERセクション

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> yahoo.co.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57517 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

ここでは、statusに注目します。

NOERROR：正常にクエリが実行されている

NXDOMAIN：ドメインが存在しない

REFUSED：何らかの理由でクエリが拒否されている

NOERROR以外のstatusが返っている場合は、そのクエリは失敗しているので、注意しましょう。

QUESTIONセクション

;; QUESTION SECTION: ;yahoo.co.jp. IN A

DNSへの問い合わせ内容が表示されています。ここでは、yahoo.co.jpドメインのAレコードを問い合わせしています。INはインターネットの略で、クエリ全般これがついているので、とりあえず「そんなもんだ」と覚えておきましょう。

ANSWERセクション

;; ANSWER SECTION: yahoo.co.jp. 60 IN A 182.22.59.229 yahoo.co.jp. 60 IN A 183.79.135.206

問い合わせ内容に対する返答です。ここでは、yahoo.co.jpのエイリアス（Aレコード）に、２つのIPアドレスがあることがわかります。また、ここの60はTTL（キャッシュの生存期間）を表します。

試しに、このIPアドレスにWebブラウザでアクセスしてみてください。yahooのトップページが表示されます。

締めのセクション

;; Query time: 5 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Fri Feb 2 23:53:47 2018 ;; MSG SIZE rcvd: 61

最後に、クエリにかかった時間や時刻が表示されます。ここで一番大事なのが、SERVER。ここに利用したDNSサーバーが表示されます。

digコマンドにおいて、DNSサーバーの指定は必須ではありません。そして、digコマンドを実行した環境により利用されるDNSサーバーは異なるので、「あっちとこっちで、結果が違うやん」という場合、大抵はこのクエリに利用したDNSサーバーが異なっていたというパターンが多いです。

ちなみに、サーバー名の後ろ「#53」は、DNSクエリに利用したポート番号53を表しています。Route 53の名前の由来ですね。

digコマンドの別のオプション

digコマンドには、他にも便利なオプションが存在するので、それらを紹介します。

結果をシンプルに表示したい

+shortオプションを利用すると、クエリ結果がシンプルに表示されます。

$ dig yahoo.co.jp +short 182.22.59.229 183.79.135.206

シェルスクリプトの中で使ったりするには、便利ですね。

ルートからDNSをたどる

+traceオプションを利用すると、強制的にルートサーバーから順番にたどることができます。

$ dig yahoo.co.jp +trace

再帰問い合わせをしない

+norecオプションを利用すると、再帰問い合わせをオフにして、名前解決を実行します。

$ dig yahoo.co.jp +norec

EC2でdigコマンドをあれこれ試してみる

ここから、EC2でdigコマンドをあれこれ試してみます。もう一度、yahoo.co.jpに対して、クエリを流します。

$ dig yahoo.co.jp ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> yahoo.co.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57517 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;yahoo.co.jp. IN A ;; ANSWER SECTION: yahoo.co.jp. 60 IN A 182.22.59.229 yahoo.co.jp. 60 IN A 183.79.135.206 ;; Query time: 5 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Fri Feb 2 23:53:47 2018 ;; MSG SIZE rcvd: 61

VPC内で利用するネームサーバ（DNS）のIPアドレスは？

ここでポイントなのが、DNSクエリを発行した時に利用されるDNSサーバ。digの結果を確認すると、下の方、;; SERVER: 10.0.0.2#53(10.0.0.2)で、DNSサーバとして、10.0.0.2のプライベートIPアドレスを利用しています。

これは、VPC内のサブネット内であらかじめAWS側でDNSサーバとして予約されているIPアドレスで、サブネット内IPアドレスの2つ目が、Amazonが提供するDNSサーバとして利用されます。

今回は、サブネットのCIDRが10.0.0.0/24なので、DNSサーバに10.0.0.2が割り当てられているということになります。

詳細は、公式ドキュメントの「VPC での DNS の使用 - Amazon Virtual Private Cloud」を参照ください。

ちなみにこのアドレスは、下記ファイルに記載されています。

$ cat /etc/resolv.conf ; generated by /sbin/dhclient-script search ap-northeast-1.compute.internal options timeout:2 attempts:5 nameserver 10.0.0.2

このファイルを編集すればデフォルトで利用するDNSサーバを変更できますが、恐らくはアンチパターンなので安易な変更はやめておきましょう。

Amazon提供のDNSサーバーをVPC内から利用すると、TTLが最大60秒？

上で説明したAmazon提供のDNSですが、あれこれ試してみた結果、VPC内から発行する全てのクエリのTTLが上限が60秒に設定されるようです。

yahoo.co.jpへのクエリで、DNSサーバーにAmazon提供DNSと、Googleが提供するグローバルDNS（8.8.8.8）を利用した時の差分がこちら。

$ dig @10.0.0.2 yahoo.co.jp > dns_amazon.txt $ dig @8.8.8.8 yahoo.co.jp > dns_google.txt $ diff dns_amazon.txt dns_google.txt 2c2 < ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> @10.0.0.2 yahoo.co.jp --- > ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> @8.8.8.8 yahoo.co.jp 6c6 < ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28002 --- > ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 94 13,14c13,14 < yahoo.co.jp. 60 IN A 182.22.59.229 < yahoo.co.jp. 60 IN A 183.79.135.206 --- > yahoo.co.jp. 211 IN A 182.22.59.229 > yahoo.co.jp. 211 IN A 183.79.135.206 16,18c16,18 < ;; Query time: 5 msec < ;; SERVER: 10.0.0.2#53(10.0.0.2) < ;; WHEN: Sat Feb 3 22:41:45 2018 --- > ;; Query time: 37 msec > ;; SERVER: 8.8.8.8#53(8.8.8.8) > ;; WHEN: Sat Feb 3 22:41:56 2018

ANSWERセクションのAレコード部分のTTLをみると、VPC内のAmazonDNSを利用した場合60、GoogleグローバルDNSを利用した時に211になっています。

逆に、TTLが5秒など60秒より短めに設定されているレコードの場合は、5秒で返却されます。

この挙動について公式ドキュメントが見当たらなかったのですが、VPC内からDNSを利用する場合は、TTLを長く設定する必要性がないので、最大60秒と短めに設定されていると推察されます。ただ、この仕様は将来的に変更される可能性もありますので、あくまで現時点での挙動として認識していただければと思います。

同一VPC内への名前解決を試してみた

試しに、パブリックリソースではなく、同一VPC内に作った別のEC2インスタンスのDNSホスト名に対して名前解決してみます。

$ dig ec2-176-32-88-158.ap-northeast-1.compute.amazonaws.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> ec2-176-32-88-158.ap-northeast-1.compute.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33890 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;ec2-176-32-88-158.ap-northeast-1.compute.amazonaws.com. IN A ;; ANSWER SECTION: ec2-176-32-88-158.ap-northeast-1.compute.amazonaws.com. 20 IN A 10.0.0.145 ;; Query time: 1 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Sat Feb 3 00:08:10 2018 ;; MSG SIZE rcvd: 88

同じように、10.0.0.2に問い合わせて、プライベートIPアドレスの10.0.0.145がかえってきました。まぁ当然の仕様ですね。

Route 53のプライベートホストゾーンを作成し、DNSレコードを編集してみる

AWSのRoute 53には、プライベートホストゾーンという、VPC内専用のDNSレコードを作成する機能があります。DNSサーバーの構築は素人にはなかなか敷居が高いですが、Route 53を利用して、お手軽にDNSレコードを編集してみましょう。

参考：プライベートホストゾーンの使用 - Amazon Route 53

AWSコンソールから[Route 53]を開き、[Create Hosted Zone]から設定します。VPC IDには、このプライベートホストゾーンを割り当てるVPCを設定します。

そうすると、NSレコードとSOAレコードがセットされたプライベートホストゾーンが自動的に作成されます。

試しに、VPC内のEC2からdigで確認してみると、先程作成したレコードが登録されているのがわかります。

$ dig ANY example.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> ANY example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2254 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;example.com. IN ANY ;; ANSWER SECTION: example.com. 60 IN SOA ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400 example.com. 60 IN NS ns-1536.awsdns-00.co.uk. example.com. 60 IN NS ns-0.awsdns-00.com. example.com. 60 IN NS ns-512.awsdns-00.net. example.com. 60 IN NS ns-1024.awsdns-00.org. ;; Query time: 2 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Sat Feb 3 02:32:50 2018 ;; MSG SIZE rcvd: 225

Aレコードを設定し、独自ドメインでEC2に名前解決する

このゾーンに対して、EC2インスタンスプライベートIPアドレスへのAレコードを設定します。

結果を確認します。

$ dig app02.example.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> app02.example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62131 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;app02.example.com. IN A ;; ANSWER SECTION: app02.example.com. 16 IN A 10.0.0.145 ;; Query time: 0 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Sat Feb 3 02:41:13 2018 ;; MSG SIZE rcvd: 51

無事、app02.example.comを利用して、プライベートIPアドレスへの名前解決ができるようになりました。

VPC内でEC2インスタンスやRDSに接続する時、IPアドレスやRDSのエンドポイントを直接指定せずに、プライベートホストゾーンで別名を指定してそれを利用する方法も有ります。そうすると、インスタンスやRDSの再作成時に、変更箇所をRoute 53の設定だけで済ますことができ、EC2内の設定を変更する必要がありません。

運用保守時には非常に便利な機能なので、適宜ご活用いただければと思います。

適当なTXTレコードを設定してみる

他のレコードも設定できます。TXTレコードの場合は、TypeにTXTを指定しましょう。

$ dig txt hamako9999.example.com ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.56.amzn1 <<>> txt hamako9999.example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25113 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;hamako9999.example.com. IN TXT ;; ANSWER SECTION: hamako9999.example.com. 60 IN TXT "dosukoi wassyoi" ;; Query time: 1 msec ;; SERVER: 10.0.0.2#53(10.0.0.2) ;; WHEN: Sat Feb 3 03:51:32 2018 ;; MSG SIZE rcvd: 68

無事、「dosukoi wassyoi」が返却されましたね。よござんす！！

digコマンドとRoute 53を使って、DNSについて理解を深めよう！

AWSのVPCにEC2を作成し、Amazon提供のDNSサーバーの挙動と、Route 53によるプライベートホストゾーンのレコード編集結果を、digコマンドでいろいろ試してみました。

digコマンドは機能が豊富で非常に便利なのですが、できることが多いがゆえに、その結果の見方が複雑であったり、動作がわかりにくい点もあるんじゃないでしょうか。正直自分も、最初は「ええ？これどないなってんねん？」となってしまいました。

今回の記事をきっかけに、digコマンドとDNSについて理解が深まれば幸いです。

それでは、今日はこのへんで。濱田（@hamako9999）でした。

おすすめ書籍

自分がDNSを勉強するにあたり、読んでいる本です。対話形式なので記述が冗長に感じるかもですが、丁寧に順を追って解説してくれるので、非常に分かりやすい。「DNS学ぶんだったら、最初はコレでええやろ」と自信をもってオススメします。