Terraform变量验证无理由导致计划失败,求排查错误原因
问题描述
我有一个Terraform模块,其policy_statements变量配置了如下验证规则:
variable "policy_statements" { description = "要创建的策略语句" type = map(object({ path = string capabilities = set(string) })) validation { condition = alltrue([ for stmt in var.policy_statements : contains(["create", "read", "update", "patch", "delete", "list"], stmt.capabilities) ]) error_message = "capabilities的有效值为(\"create\", \"read\", \"update\", \"patch\", \"delete\", \"list\")." }
我在另一个Terraform模块中调用该模块:
module "policies" { source = "../../../../path/to" for_each = var.policies policy_statements = each.value }
外层模块中policies变量声明为:
variable "policies" { description = "要创建的策略语句" type = map(any) }
执行时出现错误:
│ Error: Invalid value for variable │ │ on main.tf line 38, in module "policies": │ 38: policy_statements = each.value │ ├──────────────── │ │ var.policy_statements is map of object with 2 elements │ │ Valid values for capabilities are ("create", "read", "update", "patch", │ "delete", "list"). │ │ This was checked by the validation rule at │ ../../../../modules-terraform/vault/policies/variables.tf:12,3-13.
外层模块通过terragrunt.hcl读取policies变量:
locals { policies = yamldecode(file("config.yaml")) } inputs = { policies = local.policies }
对应的config.yaml内容为:
policies: policy-test-1: capabilities: - read - create path: /foo/lala policy-test-2: capabilities: - update - delete path: /foo/lala
移除验证规则后计划就能成功执行,请问我的验证规则哪里出错了?
问题根源与解决方法
你的验证规则逻辑错误:stmt.capabilities是集合(set)类型,但你用contains函数直接检查这个集合是否存在于字符串列表中——列表里的元素是单个字符串,和集合类型不匹配,导致验证永远失败。
正确逻辑应该是:遍历每个策略语句的capabilities集合中的每一个元素,确保所有元素都属于允许的有效值列表。
修改后的验证规则如下:
validation { condition = alltrue([ for stmt in var.policy_statements : alltrue([ for cap in stmt.capabilities : contains(["create", "read", "update", "patch", "delete", "list"], cap) ]) ]) error_message = "capabilities的有效值为(\"create\", \"read\", \"update\", \"patch\", \"delete\", \"list\")." }
额外优化建议
- 外层模块的
policies变量使用map(any)会丢失类型约束,建议改成和内层模块一致的类型定义,提前发现配置错误:
variable "policies" { description = "要创建的策略语句" type = map(object({ path = string capabilities = set(string) })) }
yamldecode读取YAML列表时会得到Terraform的list类型,虽然Terraform会自动转成set,但如果需要显式控制,可在调用模块时转换:
policy_statements = { path = each.value.path capabilities = toset(each.value.capabilities) }
内容的提问来源于stack exchange,提问作者pkaramol
相关产品推荐
相关产品推荐

