HCLコードの自動生成を利用してRoute53管理のドメインをterraform管理にimportする
terraformにRoute53管理のドメインをimportする
terraformはAWSマネジメントコンソール等で作成した既存リソースも、importを使うことでterraform管理に取り込むことができます。terraformでIaCするのが大好きな私は、プライベートで持っている大昔に取ったドメインもterraformにimportしてみます。
大体の流れ
- import内容を記述した
.tf
ファイルを用意する terraform plan -generate-config-out
でHCLコード(.tf
ファイル)を生成する- 生成したコードを微調整する
terraform apply
でimport完了
generate-config-outオプション
generate-config-outオプションを使うことで取り込むAWSリソースの.tf
ファイルを生成することができます。
これを使わなくてもAWSリソースのimportはできますが、importはあくまでterraformの状態管理ファイルである.tfstate
に取り込むのみなので、.tf
ファイルは作成されません。.tf
ファイルは別途用意する必要があります。generate-config-out
はこれを生成してくれるということですね。
公式ドキュメントを見てみます。
terraformバージョン1.5から導入された機能ですが、いまだに試験的な機能の扱いのようです🤔
やってみる
terraform管理のリポジトリにdomain
ディレクトリを掘ってその中にファイルを配置することにします。
作ったファイルは3つだけ。
% tree ./domain
./domain
├── import.tf
├── locals.tf
└── terraform.tf
import.tf
import {
to = aws_route53domains_registered_domain.my_domain_com
id = local.my_domain
}
import {
to = aws_route53_zone.my_domain_com
id = local.zone_id
}
import {
to = aws_route53_record.my_domain_com_ns
id = "${local.zone_id}_${local.my_domain}_NS"
}
import {
to = aws_route53_record.my_domain_com_soa
id = "${local.zone_id}_${local.my_domain}_SOA"
}
import {
to = aws_route53_record.my_domain_com_a
id = "${local.zone_id}_www.${local.my_domain}_A"
}
AWSリソースをterraformのtfstateに取り入れるimportブロックです。
aws_route53_recordの書き方がちょっとめんどくさくて、idの形式が"
これに限らず、importブロックの書き方はterraformの各リソースのドキュメントに書いてあるので見ましょう。
ゾーンIDはAWSマネージメントコンソールから確認しましょう。
locals.tf
locals {
my_domain = "私のドメイン"
zone_id = "コンソール上で確認したゾーンID"
}
ドメインとゾーンIDを別ファイルのlocalsに。
terraform.tf
terraform {
required_version = "~> 1.13.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
backend "s3" {
bucket = <バケット名>
region = "ap-northeast-1"
key = "tfstate/dev/domain.tfstate"
}
}
provider "aws" {
region = "ap-northeast-1"
}
バージョンやtfstateの置き場所、providerの定義です。このへんのファイル分割はプロジェクトにより色々ありますが、私は理由がなければterraform.tf
にまとめちゃうことが多いです。
ではterraform plan -generate-config-out
を使って、HCLコードを作成してみます。
terraform init
terraform plan -generate-config-out="route53.tf"
-generate-config-out
の引数にはHCLコードを出力するファイル名を指定します。既存のファイルパスはNGです。
以下のようにroute53.tfが出力されました。
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "my_domain_com"
resource "aws_route53domains_registered_domain" "my_domain_com" {
admin_privacy = true
auto_renew = true
billing_privacy = true
domain_name = "example-company.com"
registrant_privacy = true
tags = {}
tags_all = {}
tech_privacy = true
transfer_lock = true
admin_contact {
address_line_1 = "1-1-1 Shibuya"
address_line_2 = null
city = "Shibuya-ku"
contact_type = "PERSON"
country_code = "JP"
email = "admin@example-company.com"
extra_params = {}
fax = null
first_name = "Taro"
last_name = "Yamada"
organization_name = null
phone_number = "+81.312345678"
state = null
zip_code = "150-0002"
}
billing_contact {
address_line_1 = "1-1-1 Shibuya"
address_line_2 = null
city = "Shibuya-ku"
contact_type = "PERSON"
country_code = "JP"
email = "billing@example-company.com"
extra_params = {}
fax = null
first_name = "Taro"
last_name = "Yamada"
organization_name = null
phone_number = "+81.312345678"
state = null
zip_code = "150-0002"
}
name_server {
glue_ips = []
name = "ns-170.awsdns-21.com"
}
name_server {
glue_ips = []
name = "ns-1554.awsdns-02.co.uk"
}
name_server {
glue_ips = []
name = "ns-575.awsdns-07.net"
}
name_server {
glue_ips = []
name = "ns-1364.awsdns-42.org"
}
registrant_contact {
address_line_1 = "1-1-1 Shibuya"
address_line_2 = null
city = "Shibuya-ku"
contact_type = "PERSON"
country_code = "JP"
email = "registrant@example-company.com"
extra_params = {}
fax = null
first_name = "Taro"
last_name = "Yamada"
organization_name = null
phone_number = "+81.312345678"
state = null
zip_code = "150-0002"
}
tech_contact {
address_line_1 = "1-1-1 Shibuya"
address_line_2 = null
city = "Shibuya-ku"
contact_type = "PERSON"
country_code = "JP"
email = "tech@example-company.com"
extra_params = {}
fax = null
first_name = "Taro"
last_name = "Yamada"
organization_name = null
phone_number = "+81.312345678"
state = null
zip_code = "150-0002"
}
}
# __generated__ by Terraform from "Z01921833I123456789"
resource "aws_route53_zone" "my_domain_com" {
comment = null
delegation_set_id = null
force_destroy = null
name = "example-company.com"
tags = {}
tags_all = {}
}
# __generated__ by Terraform
resource "aws_route53_record" "my_domain_com_soa" {
allow_overwrite = null
health_check_id = null
multivalue_answer_routing_policy = false
name = "example-company.com"
records = ["ns-170.awsdns-21.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"]
set_identifier = null
ttl = 900
type = "SOA"
zone_id = "Z01921833I123456789"
}
# __generated__ by Terraform
resource "aws_route53_record" "my_domain_com_ns" {
allow_overwrite = null
health_check_id = null
multivalue_answer_routing_policy = false
name = "example-company.com"
records = ["ns-1364.awsdns-42.org.", "ns-1554.awsdns-02.co.uk.", "ns-170.awsdns-21.com.", "ns-575.awsdns-07.net."]
set_identifier = null
ttl = 172800
type = "NS"
zone_id = "Z01921833I123456789"
}
# __generated__ by Terraform
resource "aws_route53_record" "my_domain_com_a" {
allow_overwrite = null
health_check_id = null
multivalue_answer_routing_policy = false
name = "www.example-company.com"
records = ["111.111.222.222"]
set_identifier = null
ttl = 300
type = "A"
zone_id = "Z01921833I123456789"
}
確かに出力されましたが、aws_route53domains_registered_domain
を見るとわかる通り、個人情報モリモリです。このままでは例えプライベートリポジトリでもコミットしたくないです(上記コードの個人情報は記事用に適当なものに変えてます)。
個人情報含め、コードに書いておく必要のないものは消します。
特に登録ドメインのaws_route53domains_registered_domainはほとんどの引数がオプショナルです。
削除してplanを取ってみます。-generate-config-out
はもう必要ありません。
terraform plan
...
│ Error: Missing required argument
│
│ with aws_route53_record.my_domain_com_soa,
│ on domain.tf line 3:
│ (source code not available)
│
│ "multivalue_answer_routing_policy": all of `multivalue_answer_routing_policy,set_identifier` must be specified
╵
エラーが出ました。
ルーティングポリシーの問題のようです。シンプルルーティングポリシーならmultivalue_answer_routing_policy
, set_identifier
は必須でないので削除します。
修正してplanが通り、他にも多少整理して、こんな感じになりました。
resource "aws_route53domains_registered_domain" "my_domain_com" {
admin_privacy = true
auto_renew = true
billing_privacy = true
domain_name = "example-company.com"
registrant_privacy = true
tech_privacy = true
transfer_lock = true
name_server {
glue_ips = []
name = "ns-170.awsdns-21.com"
}
name_server {
glue_ips = []
name = "ns-1554.awsdns-02.co.uk"
}
name_server {
glue_ips = []
name = "ns-575.awsdns-07.net"
}
name_server {
glue_ips = []
name = "ns-1364.awsdns-42.org"
}
}
resource "aws_route53_zone" "my_domain_com" {
delegation_set_id = null
force_destroy = null
name = "example-company.com"
}
resource "aws_route53_record" "my_domain_com_soa" {
allow_overwrite = null
health_check_id = null
name = "example-company.com"
records = ["ns-170.awsdns-21.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"]
ttl = 900
type = "SOA"
zone_id = "Z01921833I123456789"
}
resource "aws_route53_record" "my_domain_com_ns" {
allow_overwrite = null
health_check_id = null
name = "example-company.com"
records = ["ns-1364.awsdns-42.org.", "ns-1554.awsdns-02.co.uk.", "ns-170.awsdns-21.com.", "ns-575.awsdns-07.net."]
ttl = 172800
type = "NS"
zone_id = "Z01921833I123456789"
}
resource "aws_route53_record" "my_domain_com_a" {
allow_overwrite = null
health_check_id = null
name = "www.example-company.com"
records = ["111.111.222.222"]
ttl = 300
type = "A"
zone_id = "Z01921833I123456789"
}
他にも必要ない項目があって冗長だし、リテラルじゃなくて参照に変えたほうがいいとか色々あるけど(zone_idとか)、まぁ見通せるレベルなんで一旦OKです。
applyしてみます。
terraform apply
...
Apply complete! Resources: 5 imported, 0 added, 1 changed, 0 destroyed.
成功しました。1 changed
が出ているのはmanaged by terraform
のコメントがついただけみたいなので問題ないです。
うーんでもちゃんとterraformに取り込めたかな?動作確認としてホストゾーンにAレコードを新しく作ってみます。以下コードを追加します。
# Aに割り当てるElasticIPを取る
resource "aws_eip" "sample_eip" {
domain = "vpc"
}
resource "aws_route53_record" "sample_eip_record_a" {
name = "sample.my-domain.com"
records = ["${aws_eip.sample_eip.public_ip}"]
ttl = 300
type = "A"
# 取り込んだゾーンを参照で指定
zone_id = aws_route53_zone.como-ran_com.id
}
applyします。
terraform apply
...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
成功したようです。AWSコンソールで確認してみましょう。
ちゃんとできてます!
まとめ
冗長だったり、DRYじゃなかったりで多少の手直しは必要ですが、それでもterraform plan -generate-config-out
によるHCLコードの自動生成は楽ですね。手で書くと変数を必須か否かドキュメント見ながらプランプランすることになるので。