GCEからAWS Route53のPrivate DNSで名前解決を行う。

## はじめに

マルチクラウドの環境おいてGCPのCompute EngineからVPN接続されたAWSのRoute53のPrivate DNSで名前解決を行い、AWS EC2のインスタンスへアクセスする設定について記載していきます。
この記事ではGCPとAWSの設定がすんでいることを前提としています。VPNの設定に関しては以下の記事が参考になるかと思います。

- [Amazon VPCとGoogle Compute EngineをVPN接続する](https://dev.classmethod.jp/cloud/vpn-interconnect-amazon-vpc-and-gce)
- [[IPSec-VPN] クラウド間(GCP⇔AWS)通信](https://qiita.com/coga2000/items/fcdf3936437d716c1e8e)

## 問題点

GCPとAWSのVPNの設定を行い、いざEC2とGCE間での通信行おうとして、とりあえずpingで接続確認。IPでの接続確認はVPN設定で当然行えるのだけれど、ドメインでの接続確認が... 

```
ping: <ホスト>: Name or service not known
```
:scream:

上記ドメインの名前解決はAWSのRoute53のPrivate DNSに設定されていて、そこで名前解決されていない様子。ちなみにPublic DNSだと問題なく名前解決を行い接続確認が行える(当たり前だけど...)。

これは色々面倒臭そう...

## AWS側の設定

まずRoute53のPrivate DNSは、対象のVPCネットワーク内でなければ参照が行えない。そのためにVPC外からPrivate DNSを参照するには、ひと工夫することが必要になってきます。以下の記事を参照すると、いくつかの方法はあるのだけれども、今回は一番簡単に出来そうなAWS Directory Service Simple AD経由で名前解決を行う方法を採用しました。

- [AWSハイブリッド構成のDNS設計レシピ](https://dev.classmethod.jp/cloud/aws-hybrid-cloud-dns-designs/)

Directory Service Simple ADを利用してのPrivate DNSでの名前解決の方法は[AWS Directory Service(Simple AD)を利用したオンプレミスからのPrivate Hosted Zone名前解決](https://dev.classmethod.jp/cloud/aws/private-dns-forwarder-by-simple-ad/)が参考になります。

AWSのDirectory Serviceから「ディレクトリのセットアップ」を行います。ディレクトタイプの選択で[Simple AD]を選択。

![スクリーンショット 2018-08-18 15.56.15.png](https://qiita-image-store.s3.amazonaws.com/0/218189/12398f8c-0ac1-aeba-3749-c72bb7baa09d.png)

次にディレクトリの情報を入力しますが、ポイントとしてはディレクトリのDNS名を、Private DNSで設定されたドメインメイトは**異なるドメイン名**を入力します。

![スクリーンショット 2018-08-18 16.00.13.png](https://qiita-image-store.s3.amazonaws.com/0/218189/51a313d6-866e-abfd-bac8-cd60738b6440.png)

あとはVPCとサブネットの指定を行い、ディレクトリの作成を行います。

![スクリーンショット 2018-08-18 16.03.09.png](https://qiita-image-store.s3.amazonaws.com/0/218189/9a42d24c-f501-3dc0-4d05-3f2d7a49c2e8.png)

作成されたディレクトリの詳細情報を参照すると、ディレクトリに対してDNSアドレスが設定されていることが確認出来ます。VPC外のホストから、このアドレスに対してDNS名前解決を行うとPrivate DNSに設定された内容で名前解決行うことが出来ます。

![スクリーンショット 2018-08-18 16.07.23.png](https://qiita-image-store.s3.amazonaws.com/0/218189/50d2508a-26d4-e5d2-1f0e-6ff6024c1b6d.png)

試しにGCE上から以下のようにDNS指定で名前解決を行うと成功知ることが確認出来ます。

```shell
# nslookupの第２引数でDNSアドレスを指定する。
$ nslookup <ホスト> 172.31.46.186
Server:         172.31.46.186
Address:        172.31.46.186#53
Non-authoritative answer:
Name:   <ホスト>
Address: 172.16.15.146
```

AWS側の設定はこれでOK!

## GCE側の設定

次にGCE側の設定を行なっていきます。今回はGCEのブートイメージとして`Debian GNU/Linux 9 (stretch)`を前提に説明を行います。
DNSサーバのIPアドレスがわかっているんだから、あとは`resolv.conf`に追記してあげればOKかなと思っていましたが...
以下を参照すると

- [内部 DNS](https://cloud.google.com/compute/docs/internal-dns)

> デフォルトでは、ほとんどのLinuxディストリビューションがDHCP情報をresolv.confに格納しています。Compute Engineの各インスタンスは、DHCP リースを 24 時間ごとに更新するように設定されています。ゾーン DNSに対して有効化されているインスタンスの場合は、DHCPリースは 1 時間ごとに期限切れとなります。DHCP更新によってこのファイルが上書きされるため、それまでに行われた変更が元に戻されます。

あれ、直接書いちゃいけないってこと?
それからの四苦八苦を省略し、色々と調べた結果DHCP側の設定ファイル`/etc/dhcp/dhclient.conf`を変更しなければいけないことが分かりました。:clap:
`/etc/dhcp/dhclient.conf`を覗いてみると以下のような感じでDHCPへのリクエスト設定を行なっています。

```conf
・・・
send host-name = gethostname();
request subnet-mask, broadcast-address, time-offset, routers,
        domain-name, domain-name-servers, domain-search, host-name,
        dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers,
        netbios-name-servers, netbios-scope, interface-mtu,
        rfc3442-classless-static-routes, ntp-servers;
・・・
```

このHDCPへのリクエスト結果に対して、`resolv.conf`へDNSの追加を行うには、設定ファイルに対して以下を追加すればOKです。指定するIPアドレスはSimple ADのDNSアドレスとなります。

```conf
prepend domain-name-servers 172.31.46.186;
prepend domain-name-servers 172.31.6.6;
```

あとはネットワークの再起動。

```shell
$ sudo service networking restart
```

再度nslookupでの確認（DNS指定なし）を行なってみると、無事に名前解決が行えるようになりました。:clap:

```shell
$ nslookup <ホスト>
Server:         172.31.46.186
Address:        172.31.46.186#53
Non-authoritative answer:
Name:   <ホスト>
Address: 172.16.15.146
```

`/etc/resolv.conf`も見てみると、DNSサーバの追加が無事にされていることが確認できます。

```shell
$ cat /etc/resolv.conf 
domain c.<プロジェクト名>.internal
search c.<プロジェクト名>.internal. google.internal.
nameserver 172.31.6.6
nameserver 172.31.46.186
nameserver 169.254.169.254
```

## おまけ

GCEにはインスタンス起動時の独自のスクリプト実行として、起動スクリプトの仕組みがあります。

- [起動スクリプトの実行](https://cloud.google.com/compute/docs/startupscript)

起動スクリプトして今回DNSの追加処理を行うと便利です。インスタンス作成時の「管理」->「自動化」->「起動スクリプト」の欄に、実行するスクリプトを記述することで、実行することができます。

![スクリーンショット 2018-08-18 20.18.58.png](https://qiita-image-store.s3.amazonaws.com/0/218189/94794551-d49a-1859-ebfa-d148839d0268.png)


今回は以下のスクリプトを記載することで、起動時のDNSサーバの設定を行うことができます。

```shell
echo 'prepend domain-name-servers 172.31.6.6;' >> /etc/dhcp/dhclient.conf
echo 'prepend domain-name-servers 172.31.46.186;' >>  /etc/dhcp/dhclient.conf
sudo service networking restart
```

Google Cloud Storage上のファイルを起動スクリプトとして実行することもできるので、興味ある方はチャレンジしてみてください。

## 終わりに

今回はVPN接続されたAWSとGCPの環境に置いて、GCEからRoute53のPrivate DNSにおける名前解決方法について記載しました。
今後はGKEなどからも検証していけたらいいかな。