前書き
本記事では、Terraform を使用して、AWS Certificate Manager(ACM)
の証明書作成と、Route53 を用いた DNS 検証の方法について、備忘録も兼ねて構築内容を記載する。
ACMの概要
ACM(AWS Certificate Manager)は、AWS 上で SSL/TLS 証明書を簡易に発行・管理するサービスである。証明書の発行、更新、失効を自動化できるため、証明書管理の負担を大きく軽減できる。
ACM では、以下の二つの証明書管理方式をサポートする。
- AWS が提供する無料のパブリック証明書を発行する
- 外部で購入した証明書をインポートして利用する
ACM を利用する際の最重要ポイントは、証明書を利用する AWS サービスによって発行すべきリージョンが異なることである。特に CloudFront のみ例外で、必ず us-east-1(バージニア北部) で証明書を発行する必要がある。
主なサービスと必要リージョンは以下のとおり。
| AWSサービス | 証明書を発行すべきリージョン |
|---|---|
| CloudFront | us-east-1(バージニア北部) |
| ALB / NLB | 利用するリージョン |
| API Gateway(REST / HTTP) | 利用するリージョン |
| AppSync | 利用するリージョン |
ACM の証明書を発行する際は、DNS 検証が一般的であり、Route53 に CNAME レコードを登録することで自動的に検証が行われる。Terraform では、ACM 証明書と Route53 レコードを同時に構築することで自動検証が可能となる。
前提条件
- Terraformを動作させる環境が存在する
- AWSの認証は、AWS-Vaultの設定方法を参考に設定している
- Terraformのバージョンが
v1.50以上 - 本記事では、下記の初期状態から構築を行う
構築手順
ディレクトリ構成としては、services/ 以下に環境固有の呼び出し用コードを配置し、modules 以下にリージョン別の ACM モジュールを配置する前提で説明する。
本構成のポイントは、Route53(DNS ホストゾーン)は1つだが ACM はリージョンごとに作成する必要がある。特に CloudFront 用の証明書は us-east-1 でのみ発行可能なため、バージニア北部リージョン専用モジュールを用意する構成で実装する。
servicesフォルダー内の構築内容
-
services/main.tfでは、東京リージョン用 と バージニア北部リージョン用 の ACM モジュールをそれぞれ呼び出す -
name_prefix(サブドメイン)とzone_id/zone_name(Route53 ホストゾーン情報)を共通入力として渡す
# 東京リージョン用 ACM モジュールを呼び出して証明書の作成・検証を行う
module "acm_tokyo" {
source = "../modules/acm/tokyo"
name_prefix = local.name_prefix
zone_id = local.zone_id
zone_name = local.zone_name
}
# バージニア北部リージョン用 ACM モジュールを呼び出して証明書の作成・検証を行う
module "acm_virginia" {
source = "../modules/acm/virginia"
name_prefix = local.name_prefix
zone_id = local.zone_id
zone_name = local.zone_name
}
# example.com の Route53 ホストゾーン情報を取得する
data "aws_route53_zone" "acm_test" {
name = "example.com"
}
# 取得したホストゾーンの ID と名前をローカル変数にセットする
locals {
zone_id = data.aws_route53_zone.acm_test.zone_id
zone_name = data.aws_route53_zone.acm_test.name
}
# 証明書用サブドメインのプレフィックスを設定する
locals {
name_prefix = "acm-test"
}
services/ 層では、必要な値だけを渡すシンプルな構成としている
東京リージョンの構築内容
ALB や API Gateway など東京リージョンで利用するサービス向けの ACM 証明書を作成する。DNS 検証のため、ACM が提供する domain_validation_options から CNAME レコードを Route53 に自動生成する構成を採用する。
# 東京リージョンで ACM 証明書を発行する
resource "aws_acm_certificate" "acm_tokyo_test_com" {
domain_name = "${var.name_prefix}.${var.zone_name}"
validation_method = "DNS"
}
# 発行した証明書に対して DNS 検証を実行する
resource "aws_acm_certificate_validation" "acm_tokyo_test_com" {
certificate_arn = aws_acm_certificate.acm_tokyo_test_com.arn
# 作成した Route53 の CNAME レコードの fqdn を抽出し、証明書の DNS 検証に渡す値として一覧化する
validation_record_fqdns = [
for r in aws_route53_record.acm_tokyo_test_com : r.fqdn
]
}
# ACM が要求する DNS 検証用 CNAME レコードを Route53 に自動作成する
resource "aws_route53_record" "acm_tokyo_test_com" {
# ACM が要求する DNS 検証用 CNAME レコード情報を取り出し、Route53 レコードを自動生成するための map を作成する
for_each = {
for dvo in aws_acm_certificate.acm_tokyo_test_com.domain_validation_options :
dvo.domain_name => {
name = dvo.resource_record_name
type = dvo.resource_record_type
record_value = dvo.resource_record_value
}
}
zone_id = var.zone_id
name = each.value.name
type = each.value.type
ttl = 60
records = [each.value.record_value]
}
# 共通
variable "name_prefix" { type = string }
# ゾーンID、ゾーン名
variable "zone_id" { type = string }
variable "zone_name" { type = string }
注意
- ACM 証明書は DNS 検証が完了すれば自動更新されるため、手動更新は不要
- Route53 の
CNAMEは ACM が提示する値をそのまま登録する必要があり、コード化するとミスを防げる - 東京リージョンの証明書は CloudFront では利用できず、CloudFront 用は必ず
us-east-1で発行する必要がある
aws_route53_record.acm_tokyo_test_comの補足説明
Route53 に作成された CNAME レコードは、以下のような形になる。
aws_route53_record.acm_tokyo_test_com["acm-test.example.com"] = {
fqdn = "_abcd1234.acm-test.example.com"
name = "_abcd1234.acm-test.example.com"
type = "CNAME"
ttl = 60
records = ["_efgh5678.acm-validations.aws"]
zone_id = "Z123456789ABCDEFG"
}
| 項目名 | 説明 |
|---|---|
fqdn |
DNS に登録されるレコードの 完全なドメイン名(例: _xxxx.example.com) を示す。ACM の DNS 検証ではこの値を使って証明書を確認する |
name |
CNAME レコードの「名前」部分(左側)。Route53 に登録されるレコード名で、どの名前を検証対象とするかを示す。ACM が検証用に自動生成する値 |
type |
DNS レコードの種類。ACM の DNS 検証では常に CNAME が使われる |
ttl |
DNS レコードの有効期間(キャッシュ時間)。検証用途のため短めの値(例: 60 秒)が設定される |
records |
CNAME レコードの「宛先」部分(右側)。AWS の検証サーバーを指す値で、ACM が自動生成する |
zone_id |
このレコードが登録される Route53 のホストゾーン ID。対象ドメインの管理場所を示す |
aws_acm_certificate.acm_tokyo_test_com.domain_validation_optionsの補足説明
ACM 証明書を作成すると、DNS 検証に必要な CNAME 情報が domain_validation_options に入る。中身は AWS が自動生成する以下のような値となる。
aws_acm_certificate.acm_tokyo_test_com.domain_validation_options = [
{
domain_name = "acm-test.example.com"
resource_record_name = "_abcd1234.acm-test.example.com"
resource_record_type = "CNAME"
resource_record_value = "_efgh5678.acm-validations.aws"
}
]
| 項目名 | 説明 |
|---|---|
domain_name |
証明書を発行する対象ドメイン名。ACM がこのドメインの所有者かどうかを DNS で確認する。 |
resource_record_name |
DNS CNAME レコードの「名前」部分(左側)。Route53 に登録する際の レコード名 にあたり、「どの名前に対して検証を行うか」を示す。ACM が検証用に自動生成する特殊な値。 |
resource_record_type |
DNS レコードの種類。ACM の DNS 検証では必ず CNAME が指定される。 |
resource_record_value |
DNS CNAME レコードの「値」部分(右側)。Route53 に登録する際の 宛先(どこへ向けるか) を示し、AWS の検証サーバーを指す。これも ACM が自動生成する。 |
バージニア北部リージョンの構築内容
証明書を us-east-1(バージニア北部) で作成する。Terraform では、provider ブロックに alias を付けることで、東京リージョン以外のリージョンを安全に扱える。
# AWS プロバイダーのバージョンを指定する
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.19.0"
}
}
}
# us-east-1(バージニア北部)を利用するためのプロバイダーを定義する
provider "aws" {
alias = "virginia"
region = "us-east-1"
}
# バージニア北部で ACM 証明書を発行する
resource "aws_acm_certificate" "acm_virginia_test_com" {
provider = aws.virginia
domain_name = "${var.name_prefix}.${var.zone_name}"
validation_method = "DNS"
}
# 発行した証明書に対して DNS 検証を実行する
resource "aws_acm_certificate_validation" "acm_virginia_test_com" {
provider = aws.virginia
certificate_arn = aws_acm_certificate.acm_virginia_test_com.arn
validation_record_fqdns = [
for dvo in aws_acm_certificate.acm_virginia_test_com.domain_validation_options :
dvo.resource_record_name
]
}
# 共通
variable "name_prefix" { type = string }
# ゾーンID、ゾーン名
variable "zone_id" { type = string }
variable "zone_name" { type = string }
注意
- CloudFront は
us-east-1の証明書しか利用できないため、CloudFront 用に必ずバージニア北部で ACM を発行する - Route53 の CNAME レコードはリージョンに依存しないため、東京・バージニアどちらの ACM でも同じ DNS ゾーンで検証できる
- provider alias を忘れると全て東京リージョンで作成されるため注意が必要
用語補足
- プロバイダー : AWS のリソース(ACM、EC2、S3 など)を作成するために、Terraform 本体が AWS にアクセスする必要がある。この「AWS にアクセスするための機能」を提供するのが プロバイダー(provider)
GitHub
参考資料
- 【Terraform】(初心者向け)別リージョンにAWSリソースを作成したい
- TerraformでAWSマルチリージョンでリソースを作成する
- 【Terraform】AWSリージョンをリソース単位で設定する
感想
今回は、表題の構築内容についてまとめました。当初は 1 つの Terraform からバージニア北部リージョンに ACM をどのように構築すれば良いのか分からず、作業にかなり手間取りました。しかし、調査を進めるなかで構築方法を正しく理解でき、大きな学びにつながったと感じています。