Route 53に登録済みのドメインをTerraformで管理する

# はじめに

こんにちは。

先日、以前取得した独自ドメインに紐づいたSSL証明書を[Certificate Manager](https://aws.amazon.com/jp/certificate-manager/)でリクエストしましたが、時間が経っても発行されず困ってしまったことがありました。

結論としては独自ドメインの管理を[Route 53](https://aws.amazon.com/jp/route53/)でおこなっていたのですが、そこに紐づけられたネームサーバーが実際の値と異なっていたことが原因でした。

これを踏まえて、 **「Route 53で登録済みのドメインをTerraformで管理」** してみたところすごく良かったので皆さんにシェアしたいと思います。

:::note warn
**注意点**

この記事には以下のことは記載されていません。ご了承ください。

- Route 53やTerraform、ドメイン管理に関する諸々の詳細な解説
- Route 53にドメインを登録する方法(これからの内容は、すでにRoute 53にドメインを登録しているという仮定で進んでいきます)
:::

:::note info
余談ですが、[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/gs-acm-request-public.html)には「証明書の検証を72時間繰り返す」と書いてあります。しかし、[Certificate Manager](https://aws.amazon.com/jp/certificate-manager/)で証明書をリクエストして数分で発行されないなら、リクエストした側に何か問題があると思います。

実際、私は登録済みのドメインのネームサーバーとそのホストゾーンのNSレコードの値が異なっていたせいで、いつまで経っても証明書が発行されませんでした。

もし　読者の皆さんが、登録済みのドメインのネームサーバーに起因する問題を抱えているのなら、この記事がそれを解決してくれるかもしれません。
:::



# Route 53に登録したドメインでホストゾーンを作る

まずはパブリックなホストゾーンを追加してみましょう。Terraformでホストゾーンを管理するには[aws_route53_zone](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone)を使います。

```tf
resource "aws_route53_zone" "test" {
  name = "test@example.com"
}
```

# 登録済みのドメインをTerraformで管理する

冒頭に書いた通り、登録済みのドメインのネームサーバーとそのホストゾーンのNSレコードの値が異なっていたことでいつまで経っても証明書が発行されないというトラブルが起きてしまいました。

あるドメインで何回かホストゾーンを作成・削除を繰り返したり、誤って登録済みのドメインを消して復活する、、、といったことを繰り返していると、値が異なってしまうのかもしれません。(ちなみに私はコンソール操作を誤ってしまい、登録済みのドメインを消してしまったことがあります。[復活には$57ほどかかってしまいました](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/domain-restore-expired.html)。)


 
AWSのRoute 53に関するドキュメントの中で、NS レコードについてこのような記載があります。

> 作成したパブリックホストゾーンごとに、Amazon Route 53 はネームサーバー (NS) レコードと Start of Authority (SOA) レコードを自動的に作成します。これらのレコードを変更する必要はほとんどありません。

https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/SOA-NSrecords.html

Route 53にパブリックなホストゾーンを作成すると、自動でNSレコードが発行されます。

つまり、このNSレコードの値をドメインのネームサーバーとして紐づけられているようにTerraformで記述すれば冒頭で書いたような問題は生じなくなります。

**[aws_route53domains_registered_domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53domains_registered_domain)** を利用します。

:::note warn
aws_route53domains_registered_domain は他のリソースとは異なる挙動をするので注意が必要です。aws_route53domains_registered_domain はドメインを実際に登録したり、`terraform destroy`によって登録したドメインを実際に削除するようなことはしません。
:::

```tf
resource "aws_route53domains_registered_domain" "test" {
  domain_name = "test@example.com"

  name_server {
    name = aws_route53_zone.test.name_servers[0]
  }
  name_server {
    name = aws_route53_zone.test.name_servers[1]
  }
  name_server {
    name = aws_route53_zone.test.name_servers[2]
  }
  name_server {
    name = aws_route53_zone.test.name_servers[3]
  }
}
```

これにより、登録済みのドメインのネームサーバーとそのホストゾーンのNSレコードの値が一致している状態をTerraformで管理することができます。

<details><summary>補足</summary>

上のコードは<b>name_server</b>を繰り返しており、可読性が低いです。<b>dynamic</b>を用いて

```tf
resource "aws_route53domains_registered_domain" "test" {
  domain_name = "test@example.com"

   dynamic "name_server" {
    for_each = aws_route53_zone.my_domain.name_servers
    content {
      name = name_server.value
    }
  }
}
```

とする方が良いです。
</details>



:::note info
以上がRoute 53に登録済みのドメインをTerraformで管理する方法でした。

ここから先は、実際にCertificate Managerで証明書をリクエストする部分をTerraform化することについて簡単にまとめています。
:::


# TerraformでCertificate Managerに証明書をリクエストする

[aws_acm_certificate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate)を用いて、Certificate Managerに証明書をリクエストすることができます。

コードは以下の通りです。

```tf
// 証明書をリクエスト

resource "aws_acm_certificate" "test" {
  domain_name               = "test@example.com"

  validation_method = "DNS"
  key_algorithm     = "RSA_2048"
}


// リクエストした証明書をDNS検証するために、新たにレコードを登録する

resource "aws_route53_record" "test" {
  for_each = {
    for dvo in aws_acm_certificate.test.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  allow_overwrite = true
  name            = each.value.name
  records         = [each.value.record]
  ttl             = 300
  type            = each.value.type
  zone_id         = aws_route53_zone.test.zone_id
}
```

`aws_route53_record`の部分で若干クセのあるコードが現れましたが、 [こちら](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate#referencing-domain_validation_options-with-for_each-based-resources)でも紹介されているコードです。わからないところがあれば参考にしてみると良いです。


数分待てば、ホストゾーンに紐づけられた証明書が`発行済み`になると思います。

<details><summary>サブドメインを追加したい方へ</summary>

サブドメインを追加したい方は、<b>aws_acm_certificate</b>で<b>subject_alternative_names</b>を用いて下のように書けばいいです。

```tf
resource "aws_acm_certificate" "test" {
  domain_name               = "test@example.com"
  subject_alternative_names = ["*.test@example.com"]

  validation_method = "DNS"
  key_algorithm     = "RSA_2048"

}
```
</details>


# おわりに

いかがでしたでしょうか。

Route 53に登録している独自ドメインをTerraformで管理することで、ネームサーバーとホストゾーンのNSレコードが同じになるようにする方法を中心にこの記事をまとめました。

この記事が人生で初めて書いた記事だったので、言いたいことが散らばってしまった気がしています。

記事に関して誤った内容や、感想があればぜひコメントをしていただけると嬉しいです。

ありがとうございました。