为什么每个 Terraform 模块都需要适当的验证
Source: Dev.to
如果你曾经部署过 Terraform 模块,却发现有人传入了私有子网 ID 而本应是公共子网 ID,你就懂这种痛苦。部署成功了,但一切都无法工作。你花了几分钟调试,才意识到输入从一开始就是错误的。
Terraform 提供了内置的验证功能,但大多数人并未使用它们。
问题陈述
一个天真的 NAT 网关模块可能是这样写的:
variable "subnet_id" {
description = "Subnet to place the NAT Gateway in"
type = string
}
resource "aws_nat_gateway" "this" {
allocation_id = aws_eip.this.id
subnet_id = var.subnet_id
}
- 这会接受任何子网 ID——公共的、私有的,甚至是拼写错误的。
- Terraform 和 AWS 不会立即报错。
- 结果是私有子网没有互联网访问,浪费大量时间。
为变量添加验证
自 Terraform 1.0 起,你可以在变量中添加 validation 块:
variable "public_subnet_ids" {
description = "Public subnet IDs for NAT Gateway placement"
type = list(string)
validation {
condition = length(var.public_subnet_ids) > 0
error_message = "At least one public subnet ID is required."
}
validation {
condition = alltrue([for id in var.public_subnet_ids : startswith(id, "subnet-")])
error_message = "All values must be valid subnet IDs (starting with 'subnet-')."
}
}
现在,如果有人传入空列表或格式错误的 ID,terraform plan 会立即失败并给出明确的错误信息。
在资源中使用前置条件
当需要验证变量之间的关系时,可在资源的 lifecycle 中使用 precondition 块:
resource "aws_nat_gateway" "this" {
count = var.single_nat_gateway ? 1 : length(var.public_subnet_ids)
allocation_id = aws_eip.this[count.index].id
subnet_id = var.public_subnet_ids[count.index]
lifecycle {
precondition {
condition = var.single_nat_gateway || length(var.public_subnet_ids) >= length(var.private_route_table_ids)
error_message = "When using multi‑AZ NAT, you need at least as many public subnets as private route tables."
}
}
}
这会在 计划阶段 捕获架构错误,而不是在漫长的 apply 之后。
验证检查清单
| 内容 | 原因 |
|---|---|
| 非空必需列表 | 防止静默的空操作 |
ID 格式(subnet-、vpc-、sg-) | 捕获复制粘贴错误 |
| CIDR 块格式 | 对网络输入进行正则验证 |
| 互斥标志 | 如 single_nat_gateway 与 per‑AZ 模式 |
| 跨变量一致性 | 资源块中的前置条件 |
你添加的每一项验证都能减少支持工单、Slack 上的“为什么不好用?”消息,以及因调试明显错误配置而浪费的时间。
结论
这些验证在 terraform plan 时运行——零成本、零风险,并提供更快的反馈。如果你正在为 AWS 构建 Terraform 模块,建议查看 Terraform Registry 上的 HAIT 模块集合(Terraform Registry)。