Terraform配置多域名CloudFront时Route53Zone匹配错误求助
问题排查:Terraform创建子域名ACM证书时Route53Zone找不到错误
问题场景
尝试通过Terraform配置多CloudFront站点(主域名+多子域名),每个站点对应独立CloudFront分发,第一步创建ACM证书时遇到错误。
ACM证书模块(modules/acm_certificate/main.tf)
data "aws_route53_zone" "public" { name = var.domain } resource "aws_acm_certificate" "this" { domain_name = "www.${var.domain}" subject_alternative_names = ["www.${var.domain}", "${var.domain}"] validation_method = "DNS" lifecycle { create_before_destroy = true } } resource "aws_route53_record" "cert_validation" { allow_overwrite = true for_each = { for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type zone_id = data.aws_route53_zone.public.id } } name = each.value.name records = [each.value.record] ttl = 60 type = each.value.type zone_id = each.value.zone_id } resource "aws_acm_certificate_validation" "this" { certificate_arn = aws_acm_certificate.this.arn validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn] }
站点模块(sites/route53.tf)
data "aws_route53_zone" "public" { name = var.domain # base domain route53 } locals { subdomainsList = { for pv in var.project_version : pv.project => { subdomain_name = "${pv.project}.${var.domain}" #target_distribution = aws_cloudfront_distribution.engagement_hub_subdomains[pv.project] } } } module "acm_certificate_domain" { source = "../../modules/acm_certificate" # for base domain tst.example.com domain = var.domain env = var.env region = var.region dns_name = var.dns_name providers = { aws = aws aws.global = aws.global } } module "acm_certificate_subdomain" { env = var.env region = var.region dns_name = var.dns_name for_each = local.subdomainsList source = "../../modules/acm_certificate" # for sub domains domain = each.value.subdomain_name providers = { aws = aws aws.global = aws.global } }
错误信息
Error: no matching Route53Zone found with module.static_site.module.acm_certificate_subdomain["project1"].data.aws_route53_zone.public on modules/acm_certificate/main.tf line 1, in data "aws_route53_zone" "public": data "aws_route53_zone" "public" {
工作区变量:var.domain=example.com,var.project_version=[{"project": "project1", "version": "v123.1"}]
错误原因
当创建子域名project1.example.com的ACM证书时,ACM模块中的data "aws_route53_zone" "public"会用传入的var.domain(即project1.example.com)去查找Route53区域,但AWS账号中仅存在example.com的Route53公共区域,没有project1.example.com的独立区域,因此Terraform无法找到匹配的区域,抛出错误。
解决方案
提供两种可行修复方案,推荐方案二(更稳定可控):
方案一:调整模块内Route53区域查找逻辑
修改ACM模块中的data "aws_route53_zone" "public",通过正则提取主域名(最后两个域名段)来查找正确的Route53区域:
data "aws_route53_zone" "public" { # 提取主域名,适配子域名场景:project1.example.com → example.com name = regex("([^.]+\\.[^.]+)$", var.domain)[0] }
该正则会自动匹配域名的最后两个部分,无论传入的是主域名还是子域名,都能定位到正确的Route53主区域。
方案二:调用模块时传入主域名的Route53区域ID(推荐)
- 修改ACM模块变量:在
modules/acm_certificate/variables.tf中添加新变量:
variable "route53_zone_id" { type = string description = "ID of the main Route53 zone for DNS validation records" }
- 更新ACM模块代码:删除模块内的
data "aws_route53_zone" "public",直接使用传入的区域ID:
# 移除原有的data "aws_route53_zone" "public"块 resource "aws_route53_record" "cert_validation" { allow_overwrite = true for_each = { for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type zone_id = var.route53_zone_id } } name = each.value.name records = [each.value.record] ttl = 60 type = each.value.type zone_id = each.value.zone_id }
- 更新站点模块调用逻辑:在调用ACM模块时,传入主域名的Route53区域ID:
module "acm_certificate_domain" { source = "../../modules/acm_certificate" domain = var.domain env = var.env region = var.region dns_name = var.dns_name route53_zone_id = data.aws_route53_zone.public.id # 传入主区域ID providers = { aws = aws aws.global = aws.global } } module "acm_certificate_subdomain" { env = var.env region = var.region dns_name = var.dns_name for_each = local.subdomainsList source = "../../modules/acm_certificate" domain = each.value.subdomain_name route53_zone_id = data.aws_route53_zone.public.id # 传入同一主区域ID providers = { aws = aws aws.global = aws.global } }
这种方式明确指定了验证记录要写入的Route53区域,避免了自动查找的不确定性,更适合多子域名场景。
内容的提问来源于stack exchange,提问作者user3199100
相关产品推荐
相关产品推荐

