Oracle CloudのプライベートDNSを理解する

この記事は「[Oracle Cloud Infrastructure Advent Calendar 2020](https://qiita.com/advent-calendar/2020/oci)」の25日目として書いています。

# 1. プライベートDNSがリリース！

Oracle Cloud Infrastructureでは、これまでのグローバルIP用の「DNSサービス」に加えて、プライベートIP用の「プライベートDNS」が2020年11月にリリースされた。この機能によって、ComputeのプライベートIPに対して、任意のドメイン名を付けられるようになった。

プライベートDNSはフルマネージドサービスとして提供され、利用料金は無料である。

プライベートDNSは意外に複雑なのと、以前に書いた記事「[Oracle Cloud Infrastructureの名前解決の仕組み&ホスト名の変更方法](https://qiita.com/yamada-hakase/items/9c5647d22c923fc74330)」が好評なこともあり、わかりやすく書いてみたい。というか、いまのマニュアルは相当わかりづらい。

なお、前提知識として上記の記事の内容を理解していることとする。

### 1-1. 前提条件

* Oracle Cloud Infrastructure Compute
* Oracle Cloud Infrastructure Database

<font color="red">※プライベートDNSはAlways Freeでは使用不可</font>

### 1-2. 参考資料
本記事はLiveLabをベースにカスタマイズして書いている。また、FAQは簡潔にまとまっているので、一見の価値はある。

<!--
* [Announcing Oracle Cloud Infrastructure Private DNS](https://blogs.oracle.com/cloud-infrastructure/announcing-oracle-cloud-infrastructure-private-dns)
-->
* [Manual: Private DNS](https://docs.cloud.oracle.com/ja-jp/iaas/Content/DNS/Tasks/privatedns.htm)
* [Manual: Private DNS resolvers](https://docs.cloud.oracle.com/ja-jp/iaas/Content/Network/Concepts/dns.htm#Private_resolver)
* [Reference Architectures: Use private DNS in your VCN](https://docs.oracle.com/ja/solutions/private-dns/?source=:so:tw:or:awr:ocl::Cloud&SC=:so:tw:or:awr:ocl::Cloud&pcode=)
* [LiveLab: Configuring Private DNS](https://oracle.github.io/learning-library/oci-library/oci-hol/oci-private-dns/workshops/freetier/)
* [DNS FAQのPrivate DNSのセクション](https://www.oracle.com/cloud/networking/dns-faq.html)
* [A-Team Blog: Using OCI Private DNS to Resolve Private Oracle Analytics Cloud Data Source FQDNs](https://www.ateam-oracle.com/using-oci-private-dns-to-resolve-private-oracle-analytics-cloud-data-source-fqdns)

# 2. 何が便利なのか？

プライベートDNSを説明する前に、従来の機能を振り返ってみよう。デフォルトのVCN Resolverは以下の機能を持っていた。

* **各インスタンスには「*.oraclevcn.com」というFQDNが割り当てられる**
* **FQDNを使った名前解決は、同じVCN内のインスタンスに対して利用できるが、異なるVCNのインスタンスには利用できない**

そのため以下の課題があった。

* **複数VCNで構成しているネットワークでは、VCN外のインスタンスに対して名前解決できない**
* **「foo.sample.com」のような任意のドメイン名を付けられない**

この課題を解決するには、以下のいずれかの対応策が必要だった。

* **Oracle Cloud Infrastructure内にDNSサーバーを立てる**
* **オンプレミスにあるDNSサーバーを利用する（FastConnect/VPNでオンプレミスとの接続必須）**

DNSサーバーのセットアップは難しくないが、可用性やパッチ適用を考えると運用は大変だ。またオンプレミスのDNSへの登録となると、社内のネットワーク部門との調整が必要になる。そもそも任意のドメイン名を利用することは、特定のクラウドからの独立性や利便性の面で欠かせない。

そこでプライベートDNSの登場である。無料のマネージドサービスとして提供されているので使わない手はない。なお、同様の機能は他のクラウドでも提供されており、 **「Amazon Route 53プライベートホストゾーン」** や **「AzureプライベートDNS」** などがある。

# 3. テスト環境を構築する

事前準備として「[LiveLab: Configuring Private DNS](https://docs.oracle.com/pls/topic/lookup?ctx=en/solutions/private-dns&id=hol-oci-private-dns%20)」の「Lab 2: Configuring Private DNS」の手順を実行して環境を作成する。管理者ユーザーで実行するときはIAMの権限関係は省略可能だ。使用するtfファイルは[Github](https://github.com/oegentil/learning-library/tree/master/oci-library/oci-hol/oci-private-dns)からもダウンロードできる。

LiveLabに従ってResource Managerを実行すると以下のリソースが作成される。Resource Managerを使用しないで手動で作成してもかまわない。
![privatedns01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/06c8d50b-4b2b-c148-b7dc-96dc0c5f3e56.png)
Resource Managerでは、以下のオレンジ枠の部分が作成されないので手動で作成する。

![privatedns02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/79d0cdc3-1fbd-f13b-2d6e-e7155f2c364b.png)
なお、デフォルトのセキュリティ・ルールではpingが許可されてない。そのため、それぞれのサブネットのセキュリティ・リストに以下のIngressルールを追加する。

| Source | Protocol | Type |
|:-:|:-:|:-:|
| 10.0.0.0/16  | ICMP  |  8 |
| 10.10.0.0/16  | ICMP  |  8 |

# 4. プライベートDNSをテストする

プライベートDNSの機能を理解するために基本操作を試してみる。

### 4-1. 今回の目標
今回の目標は次のとおり。

* hub_vcn内のVMに対して **<ホスト名>.hubzone.com** というFQDNを割り当てる
* spoke01_vcn内のVMに対して **<ホスト名>.spokezone.com** というFQDNを割り当てる
* hub_vcnとspoke01_vcn間で、定義したFQDNを使った名前解決ができる

### 4-2. プライベートDNSゾーンとプライベートDNSビュー

ここでプライベートDNSに関する、いくつかの用語を説明する。現段階できっちり理解する必要はないが、関係性は理解してほしい。
![privatedns03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/b4b0bc65-5bea-5986-3c60-dce8ac5b9913.png)

**DNSゾーンレコード**
DNSに定義するレコード。AレコードにはIPアドレスとホスト名の関連付けを定義する。Aレコード以外も定義可能。

**プライベートDNSゾーン**
hubzone.comなど、ユーザーが定義した任意のドメイン名に属するレコードの集合。VCN内のプライベートIPなどVCN内のリソースを定義できる。

**プライベートDNSビュー**
プライベートDNSゾーンの集合。プライベートDNSで名前解決するときは、DNSリゾルバに関連付けたプライベートDNSビューを参照する。

**プライベートDNSリゾルバ**
DNSクエリを受けたとき名前解決する仕組み。デフォルトで参照するのは、VCNのプライベートDNSビューだが、同一リージョンのビューは優先順位を付けて参照できる。また、異なるリージョンのプライベートDNSやオンプレミスのDNSとの連携もできる。そのときはリスニングエンドポイントやフォワーディングエンドポイントという仕組みを使う必要がある。

### 4-3. プライベートゾーンhubzone.comを作成する

ここからの作業はOracle Cloud Infrastructureの管理コンソールで実行する。はじめにプライベートDNSソーン「hubzone.com」を作成する。

1. 左上のメニューから **[Networking]** - **[DNS Management]** をクリックする。
2. 左の **[Zones]** をクリックしてから **[Private Zones]** タブをクリックする。すると自動生成されたプライベートゾーンが表示される。
![privatedns10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/44ddc627-cbe3-7e6f-da38-9be58b8714ce.png)

3. **[Create Zone]**をクリックして、プライベートDNSゾーン**hubzone.com**を作成する。DNSプライベートビューは**hub_vcn**を選択する。
![privatedns11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/679068a7-8b5d-babb-884f-ead35b5b04e4.png)

4. 作成が終わると、デフォルトで作成されたNSレコードとSOAレコードが表示される。
**NSレコード：** ゾーン情報を管理するネームサーバーのサーバー名を定義するレコード
**SOAレコード：** ゾーンの管理情報を指定するリソースレコード
![privatedns12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/da15a676-67b9-d799-65b3-b90f88c2dbe3.png)

5. **[Add Record]** をクリックして、次のゾーンレコードを追加する。テスト目的なので、鍵マークをクリックしてTTLに30（秒）を入力する。入力が終わったら **[Submitt]** をクリックする。
　**レコードタイプ：** A
　**NAME：** server01
　**ADDRESS：** 10.0.0.2
![privatedns13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/2a4bf008-b327-ac17-faf0-3bcc19349863.png)
6. 追加したゾーンレコードを選択し、 **[Push Changes]** をクリックする。
![privatedns14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/5f5d3cf2-9a6a-f7f7-adbf-bfa617bd0452.png)
7. 確認画面が表示されるので、 **[Push Changes]** をクリックする。
![privatedns15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/57818ca9-d034-390d-8a57-b77c3d207af3.png)
8. 正常に終わると、追加したゾーンレコードが表示される。
![privatedns15-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/1e4a165f-4bee-9dbd-fcae-486d30d48dfc.png)

### 4-4. プライベートゾーンspokezone.comを作成する
同様の手順で、VCN「spoke01_vcn」にプライベートゾーン「spokezone.com」を作成する。

1. プライベートDNSゾーン **spokezone.com** を作成する。DNSプライベートビューは **spoke01_vcn** を選択する。
![privatedns16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/2feff894-6ae7-71b1-8f1b-c48535815125.png)

2. **[Add Record]** をクリックして、次のゾーンレコードを追加する。テスト目的なので、鍵マークをクリックしてTTLに30（秒）を入力する。入力が終わったら **[Submitt]** をクリックする。 
**レコードタイプ：** A
**NAME：** server02
**ADDRESS：** 10.10.0.123
![privatedns17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/17050ffe-148b-bf1d-95de-f99e97d26ec1.png)

3. 同様に **[Push Changes]** を実行し、登録されていることを確認する。

### 4-5. 動作確認する

追加したDNSレコードが有効になっているか確認しよう。sshでhub_vcnのTestVMに接続する。

1. ホスト名を確認する。ややこしいのだがTestVMは表示名で、ホスト名はprimaryvnicである。`-f`でFQDNを表示できる。

```shell-session
$ hostname -f
primaryvnic.pub01.hubvcn.oraclevcn.com
```

2.hostコマンドでDNSの登録情報を確認すると正常に参照できる。

```shell-session
$ host server01.hubzone.com
server01.hubzone.com has address 10.0.0.2

$ host -t NS hubzone.com
hubzone.com name server vcn-dns.oraclevcn.com.

$ host -t SOA hubzone.com
hubzone.com has SOA record vcn-dns.oraclevcn.com. hostmaster.oracle.com. 4 3600 3600 3600 10
```

3.自ノードにpingを打つと「server01.hubzone.com」で名前解決できる。

```shell-session
$ ping server01.hubzone.com
PING server01.hubzone.com (10.0.0.2) 56(84) bytes of data.
64 bytes from primaryvnic.pub01.hubvcn.oraclevcn.com (10.0.0.2): icmp_seq=1 ttl=64 time=0.049 ms
^C
--- server01.hubzone.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 56ms
rtt min/avg/max/mdev = 0.049/0.056/0.064/0.010 ms
```

4.ドメイン名を付けずにpingを実行すると失敗する。これはサーチドメインに「hubzone.com」が含まれていないからだ。

```shell-session
$ ping server01
ping: server01: Name or service not known
```

サーチドメインは一般に`/etc/resolv.conf`で設定するが、Oracle Cloudではファイルを編集してはいけない。DHCPオプションでサーチドメインを追加できる。

```:/etc/resolv.conf
; Any changes made to this file will be overwritten whenever the
; DHCP lease is renewed. To persist changes you must update the
; /etc/oci-hostname.conf file. For more information see
;[https://docs.cloud.oracle.com/iaas/Content/Network/Tasks/managingDHCP.htm#notes]
;
# Generated by NetworkManager
search hubvcn.oraclevcn.com pub01.hubvcn.oraclevcn.com　★含まれていない
nameserver 169.254.169.254
```

**参考**：DHCPオプションのサーチドメイン設定
![privatedns21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/16ec46ca-2adb-b59d-7a67-82a6b44f19ab.png)


5.「server02.spokezone.com」を確認すると表示されない。これはhub_vcnのDNSリゾルバが、spoke01_vcnのDNSビューを参照していないためだ。次のステップで改善する。

```shell-session
$ host server02.spokezone.com
Host server02.spokezone.com not found: 3(NXDOMAIN)
```

### 4-6. DNSリゾルバとプライベートビューを関連付ける

先ほど名前解決に失敗したのは、hub_vcnのDNSリゾルバがspoke01_vcnのプライベートビューを参照していないためだ。そのためspoke01_vcnを参照するように変更する。

1. hub_vcnの詳細を表示する。次にDNSリゾルバ「hub_vcn」をクリックする。
![privatedns18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/b779abca-addb-c7d7-4d71-5d3aa3418cae.png)
2. 「Associated Private Views（関連付けたプライベートビュー）」が表示されるので、**[Manage Private Views]**をクリックする。
![privatedns19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/d3818dd0-7c1b-103a-29f6-19640eb69434.png)
3. リストから「spoke01_vcn」を選択し、 **[Save Changes]** をクリックする。これで関連付けができた。
![privatedns20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/9820335e-c11e-c3f5-f65a-96c571dfc310.png)
4. 再びTestVMにsshで接続してDNS情報を確認すると、参照できるようになっている。

```shell-session
$ host server02.spokezone.com
server02.spokezone.com has address 10.10.0.123

$ ping server02.spokezone.com
PING server02.spokezone.com (10.10.0.123) 56(84) bytes of data.
64 bytes from server02.pub01.spoke01.oraclevcn.com (10.10.0.123): icmp_seq=1 ttl=64 time=0.334 ms

$ ping server02.pub01.spoke01.oraclevcn.com
PING server02.pub01.spoke01.oraclevcn.com (10.10.0.123) 56(84) bytes of data.
64 bytes from server02.pub01.spoke01.oraclevcn.com (10.10.0.123): icmp_seq=1 ttl=64 time=0.546 ms
```

5.今回設定したのは「hub_vcn→spoke01_vcn」だけなので、逆方向の設定を追加すれば相互に参照できるようになる。

# 5. まとめ

### 5-1. これまでわかったこと

これまでの操作でわかったことは次のことだ。

* **プライベートDNSを使うと任意のドメイン名を定義できる**
* **ほかのVCNのプライベートDNSビューを関連付けることで、ほかのVCNに対しても名前解決ができる**

また、デフォルトのVCN and Internet Resolverは以下の順序で名前解決を試みる。

1. VCNのデフォルトプライベートビューを参照
2. 関連付けたプライベートビューを参照
3. すべてに一致しないとき、Oracle Cloud InfrastructureのInternet Resolver（169.254.169.254）を参照

ただし課題もある。それは上記2で関連付けられるのは、同一リージョンのプライベートビューに限られることだ。**DRGを利用したリモートピアリングが必要な以下の場合には、プライベートビューを参照できない。**

* オンプレミスのDNS
* 異なるリージョン

### 5-2. さらなる発展

そのときに用意されているのが、リスニングエンドポイントやフォワーディングエンドポイントという仕組みだ。ここでは説明しないが次のような仕組みになっている。詳しくはマニュアルを読んでほしい。
![privatedns04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266049/18b70b4f-5fd4-5131-ff25-6cb548c4863f.png)

また、プライベートビューはVCN単位で設定するのに対し、フォワーディングエンドポイントはサブネット単位で設定する。そのため同じVCNでも、サブネットごとに異なる設定を併用できる。

**リスニングエンドポイント／フォワーディングエンドポイントを利用した名前解決の優先順位（推測モード）**

1. 事前定義した条件に当てはまるときはフォワーディングエンドポイント先を参照
2. VCNのデフォルトプライベートビューを参照
3. 関連付けたプライベートビューを参照
4. すべてに一致しないとき、Oracle Cloud InfrastructureのInternet Resolver（169.254.169.254）を参照

また、マニュアルでユースケースとして紹介されている、アクセス元により異なる結果を返すsplit-horizon DNSもプライベートDNSを利用することで構成できる。

<font color="blue"> **注：** クロステナンシーやクロスリージョン、FastConnect/VPNによる接続はテストしていない。マニュアルの記述が甘いこともあり、推測モードで書いている部分もあるので間違っているところがあったら指摘してくださいませ。</font>

### 5-3.まとめ

* プライベートDNSを利用すると、サーバーに任意のFQDNを付けたり、異なるVCNにあるサーバーの名前解決したりできるようになる。
* いままで特定のDNSを参照するにはCustom Resolverを利用する必要があったが、プライベートDNSによってInternet and VCN Resolverでも参照できるようになった。
* VCN内のサーバーは、VCNに関連付けたプライベートビューを参照して名前解決できる。
* 異なるリージョンもしくはオンプレミスのサーバーの名前解決をするには、リスニングエンドポイント／フォワーディングエンドポイントという仕組みを使う必要がある。
* プライベートビューはVCNに設定するのに対し、フォワーディングエンドポイントはサブネットで設定する。そのため同じVCNでも、サブネットごとに異なる設定を併用できる。