TerraformでAmazon API Gatewayを構築する(カスタムドメイン編)

# はじめに
API Gateway＋Terraform記事第5弾。
API Gateway に独自ドメイン(カスタムドメイン)設定を実践する。慣れてしまえば難しいことはないけど、最初は戸惑うので整理しよう。

API Gateway の REST API は既に構築できている前提とする。
構築方法については、以下の記事を参考にしていただければ。

- 【Qiita】[TerraformでAmazon API Gatewayを構築する(基本編)](https://qiita.com/neruneruo/items/94a0e637ea1c6c95d9e4)
- 【Qiita】[TerraformでAmazon API Gatewayを構築する(ゲートウェイのレスポンス＆ステージ詳細編)
AWS](https://qiita.com/neruneruo/items/a568cd3f0542cde8c967)

なお、今回の記事では、API Gateway はリージョナルなものを使う前提としている。
エッジ最適化の場合は、ACM の証明書をバージニアで作る必要があったりするので注意が必要だ。

# 全体の流れ
カスタムドメインを設定するまでの手順は結構面倒くさい。
主に以下のステップになっている。

1. ドメインの取得
2. ドメイン認証
3. API Gateway への設定

順を追って説明していこう。

# 1. ドメインの取得
これは AWS は関係ないが、一応書いておく。

ドメインを取得して、Route53 で好きに使えるようにしておく必要がある。

ドメインの取得は、国内の有名どころでは「[お名前.com](https://www.onamae.com/)」あたり。
ここでドメインを取って、Route53 への移管を済ませよう。
Route53 への移管については、Terraform を使っても良いが、どうせ1度しかやらないのと、やった後にあまり変更もしないと思うので、以下の手順でホストゾーンを作り、Terraform ではデータソースで参照しよう。

[[AWS] 徹底図解！お名前.comで取得したDNSをAWS Route53/Cloudfrontで管理するまでの手順](https://deep-tacopots.tech/blog/12)

データソースの参照ついては、以下で良い。
ドメイン名はこの後も何度か使うので、ベタ書きではなくて ```local.domain_name``` に値を入れておこう。

```HCL
data "aws_route53_zone" "my_domain" {
  name = local.domain_name
}
```

# 2. ドメイン認証
さて、取得したドメインを使える状態にしていこう。
メール認証とDNS認証の2通りの方法があるが、Route53 で今から行うのであればDNS認証が楽なはずだ。

以下のリソースを定義していこう。

```HCL
##############################################################################
# ACM                                                                        #
##############################################################################
resource "aws_acm_certificate" "cert" {
  domain_name               = local.domain_name
  subject_alternative_names = ["*.${local.domain_name}"]
  validation_method         = "DNS"
}

resource "aws_acm_certificate_validation" "cert" {
  certificate_arn         = aws_acm_certificate.cert.arn
  validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}

##############################################################################
# Route53                                                                    #
##############################################################################
resource "aws_route53_record" "cert_validation" {
  for_each = {
    for dvo in aws_acm_certificate.cert.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             = 60
  type            = each.value.type
  zone_id         = data.aws_route53_zone.my_domain.zone_id
}
```

この中身自体は、クラスメソッド先生の以下の記事のほぼ丸パクりだし、記事中で詳しく説明されているので、そちらを読んでもらえれば。

【Developers.IO】[Terraform で AWS Certificate Manager 無料証明書を発行する（AWS Provider 3.0.0 以降の場合）](https://dev.classmethod.jp/articles/terraform-aws-certificate-validation/)

これで、API Gateway に対してドメインを設定可能な状態になった。

# 3. API Gateway への設定
さて、カスタムドメインの設定だ。

```HCL
resource "aws_api_gateway_domain_name" "my_domain" {
  domain_name              = local.domain_name
  regional_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn

  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_base_path_mapping" "my_domain" {
  api_id      = aws_api_gateway_rest_api.my.id
  stage_name  = aws_api_gateway_stage.prod.stage_name
  domain_name = aws_api_gateway_domain_name.my_domain.domain_name
}
```

```aws_api_gateway_domain_name``` ではカスタムドメインの設定を行う。
ここで、「2. ドメイン認証」の手順で作った ACM のDNS認証が必要になる。
要は、自前のドメインであることを担保するということだ。

そして、```aws_api_gateway_base_path_mapping``` では、ドメインとパスの設定を行う。
ステージと紐づけているため、この設定を行わないとアクセスができない。
また、このリソースを複数設定することにより、dev と prod のステージでパスを変えるということが可能になる。

この設定が完了すると、マネージメントコンソール上で以下のように見えるようになる。

![キャプチャ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/b205f2d3-85bb-baa7-666a-f20508edc0bf.png)
![キャプチャ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/2b519fce-56b9-2206-aaf8-99c28b4a1b73.png)

さて、最後の仕上げだ、これを Route53 のエイリアスレコードに登録してあげれば、カスタムドメインを使った API Gateway の完成だ！

```HCL
resource "aws_route53_record" "api_gateway_alias" {
  name    = aws_api_gateway_domain_name.my_domain.domain_name
  type    = "A"
  zone_id = data.aws_route53_zone.my_domain.id

  alias {
    evaluate_target_health = true
    name                   = aws_api_gateway_domain_name.my_domain.regional_domain_name
    zone_id                = aws_api_gateway_domain_name.my_domain.regional_zone_id
  }
}
```

これで、独自ドメインに対するアクセスで

```shell-session
$ curl https://xxxxxxxx.com/employee?id=00001
{
  "data": {
    "id": "00001"
    "name": "Taro-01"
    "age": "22"
  },
  "errorMessage": ""
}
```

といった具合で API を実行できるようになったぞ！