Terraformを使ってACMでSSL証明書を発行しようとした際にいくつかエラーにはまったので、記事にしておきます。
ゴール
- Terraformを使ってACMでSSL証明書を発行する
- 認証方法はRoute53を使用したDNS認証
現状
現在のtfファイルの中身はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# ホストゾーンの参照 data "aws_route53_zone" "host_zone" { # 便宜上、"example.com"としておきます name = "example.com" } # ACMのDNS検証用レコード resource "aws_route53_record" "cert" { name = aws_acm_certificate.cert.domain_validation_options[0].resource_record_name type = aws_acm_certificate.cert.domain_validation_options[0].resource_record_type records = aws_acm_certificate.cert.domain_validation_options[0].resource_record_value zone_id = data.aws_route53_zone.host_zone.zone_id ttl = 60 } # ACM証明書を定義 resource "aws_acm_certificate" "cert" { # 便宜上、"www.example.com"としておきます domain_name = "www.example.com" validation_method = "DNS" provider = aws.virginia lifecycle { create_before_destroy = true } } # レコードのチェック resource "aws_acm_certificate_validation" "cert" { certificate_arn = aws_acm_certificate.cert.arn validation_record_fqdns = [ aws_route53_record.cert.fqdn ] provider = aws.virginia } |
※Cloudfrontで使用するためバージニア北部でSSL証明書を作成しています。
このまま terraform plan をすると、エラーをはきます。
エラー①:DNSレコードの定義でエラー
エラーの内容確認
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
$ terraform plan ╷ │ Error: Invalid index │ │ on route53.tf line 22, in resource "aws_route53_record" "cert": │ 22: name = aws_acm_certificate.cert.domain_validation_options[0].resource_record_name │ │ Elements of a set are identified only by their value and don't have any separate index or key to select with, so it's only possible to perform operations across all elements of │ the set. ╵ ╷ │ Error: Invalid index │ │ on route53.tf line 23, in resource "aws_route53_record" "cert": │ 23: type = aws_acm_certificate.cert.domain_validation_options[0].resource_record_type │ │ Elements of a set are identified only by their value and don't have any separate index or key to select with, so it's only possible to perform operations across all elements of │ the set. ╵ ╷ │ Error: Invalid index │ │ on route53.tf line 24, in resource "aws_route53_record" "cert": │ 24: records = aws_acm_certificate.cert.domain_validation_options[0].resource_record_value │ │ Elements of a set are identified only by their value and don't have any separate index or key to select with, so it's only possible to perform operations across all elements of │ the set. |
インデックス系のエラーがでてますね。
DeepLでエラー文を翻訳してみると、、、
セットの要素は、その値によってのみ識別され、
選択するための個別のインデックスやキーを持たないため、
セットのすべての要素に対してのみ操作を行うことが可能です。
うーーん、いまいちよくわからない。。。
原因調査
エラー文で検索したところ、以下の記事を発見しました。
aws provider 3.0.0 以降は domain_validation_options がSet型で返ってくるようになりました。
それ以前はList型だったのでインデックスを指定できたのですが、
Set型になり順序付けされなくなったため、インデックスを指定不可となったようです。
コード修正
下記のように aws_route53_record のコードを修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# aws_route53_record のみ抜粋 # ACMのDNS検証用レコード resource "aws_route53_record" "cert" { 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 } } name = each.value.name type = each.value.type records = [ each.value.record ] zone_id = data.aws_route53_zone.host_zone.zone_id ttl = 60 } |
for文でmap型へ変換して、それをname, type, records に設定しています。
詳しい解説は以下をご覧ください
これで、terraform planをしてみると、、、まだエラーが出ています。。。
エラー②:検証待ちのFQDN指定でエラー
エラーの内容確認
1 2 3 4 5 6 7 8 9 |
│ Error: Missing resource instance key │ │ on acm.tf line 15, in resource "aws_acm_certificate_validation" "cert": │ 15: validation_record_fqdns = [ aws_route53_record.cert.fqdn ] │ │ Because aws_route53_record.cert has "for_each" set, its attributes must be accessed on specific instances. │ │ For example, to correlate with indices of a referring resource, use: │ aws_route53_record.cert[each.key] |
DNS検証用のレコードを指定している部分(validation_record_fqdns)でエラーになっています
どうやら aws_route53_record.cert もSet型で返ってきているみたいです。
コード修正
1 2 3 4 5 6 7 8 |
# aws_acm_certificate_validation のみ抜粋 # レコードのチェック resource "aws_acm_certificate_validation" "cert" { certificate_arn = aws_acm_certificate.cert.arn validation_record_fqdns = flatten([ values(aws_route53_record.cert)[*].fqdn ]) provider = aws.virginia } |
values関数を使用して、aws_route53_record.cert を Set→Listへ変換しています。
そして、Splat演算子([*])で aws_route53_record.cert 内のすべての要素からfqdnを取り出しています。
それらをflatten関数で囲むことで取り出したfqdnをリスト内に並べています。
これで無事 plan, apply両方通るコードになりました!
修正後のコード
最後に、修正後のコード全体を載せておきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# ホストゾーンの参照 data "aws_route53_zone" "host_zone" { # 便宜上、"example.com"としておきます name = "example.com" } # ACMのDNS検証用レコード resource "aws_route53_record" "cert" { 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 } } name = each.value.name type = each.value.type records = [ each.value.record ] zone_id = data.aws_route53_zone.host_zone.zone_id ttl = 60 } # ACM証明書を定義 resource "aws_acm_certificate" "cert" { # 便宜上、"www.example.com"としておきます domain_name = "www.example.com" validation_method = "DNS" provider = aws.virginia lifecycle { create_before_destroy = true } } # レコードのチェック resource "aws_acm_certificate_validation" "cert" { certificate_arn = aws_acm_certificate.cert.arn validation_record_fqdns = flatten([ values(aws_route53_record.cert)[*].fqdn ]) provider = aws.virginia } |
参考文献
コメント