Terraform编写CloudFront模块时origin_config变量默认值不兼容报错如何解决?
问题原因
Terraform 对变量的类型校验优先级远高于变量值加载逻辑:
- 你定义的
origin_config是固定结构的 object 类型,其中明确声明了domain_name是必填的 string 属性,未标记为可选。 - Terraform 会在加载 tfvars、环境变量等外部传入的变量值之前,先校验变量的默认值是否完全匹配类型约束。你的默认值缺少必填的
domain_name字段,校验直接失败,根本走不到读取 tfvars 的步骤,并非 tfvars 配置未被读取。
解决方案
根据你使用的 Terraform 版本选择对应方案即可:
方案1:使用 optional 修饰符(推荐,Terraform v0.14 及以上版本支持)
将 object 中不需要用户必填的属性标记为 optional,可以直接在修饰符中指定默认值,用户仅需传入必填的 domain_name 即可,Terraform 会自动补全其他属性的默认值:
variable "origin_config" { type = object({ domain_name = string # 必填属性,用户必须传入 protocol_policy = optional(string, "https-only") # 可选,默认值为 https-only ssl_protocol = optional(list(string), ["TLSv1.2"]) http_port = optional(number, 80) https_port = optional(number, 443) }) # 无需再写 default 块,可选属性已自带默认值 }
注意:如果使用 Terraform v0.14 ~ v1.2 版本,需要先在根模块的 Terraform 配置中启用实验特性:
terraform { experiments = [module_variable_optional_attrs] }Terraform v1.3 及以上版本 optional 已正式 GA,不需要额外配置。
方案2:兼容旧版本 Terraform
如果你的 Terraform 版本低于 0.14 不支持 optional,可以用以下两种方式处理:
方式A:补全默认值占位
在变量默认值中补一个无意义的 domain_name 占位值,用户在 tfvars 中传入的 origin_config 会完整覆盖默认值,占位值不会实际生效:
variable "origin_config" { type = object({ domain_name = string protocol_policy = string ssl_protocol = list(string) http_port = number https_port = number }) default = { domain_name = "placeholder.example.com" # 新增占位默认值,会被用户传入值覆盖 protocol_policy = "https-only" ssl_protocol = ["TLSv1.2"] http_port = 80 https_port = 443 } }
方式B:手动合并默认值
如果不想要求用户传入所有属性,可以调整变量类型为 map,通过本地值合并默认配置和用户配置:
# variables.tf variable "origin_config" { type = map(any) default = {} } # 本地值合并配置 locals { origin_config_default = { protocol_policy = "https-only" ssl_protocol = ["TLSv1.2"] http_port = 80 https_port = 443 } origin_config = merge(local.origin_config_default, var.origin_config) }
修改 CloudFront 资源中的引用为本地值即可:
resource "aws_cloudfront_distribution" "this" { origin { domain_name = local.origin_config.domain_name origin_id = local.origin_id custom_origin_config { origin_protocol_policy = local.origin_config.protocol_policy origin_ssl_protocols = local.origin_config.ssl_protocol http_port = local.origin_config.http_port https_port = local.origin_config.https_port } } }
内容的提问来源于stack exchange,提问作者yossarian2004
相关产品推荐
相关产品推荐

