如何在Terraform中动态创建安全组Ingress规则?
问题:如何基于Terraform变量添加安全组额外Ingress规则?
我正在创建一个包含标准Ingress规则的安全组,同时希望基于变量添加额外的Ingress规则。以下是我的Terraform配置代码:
variable "additional_ingress" { type = list(object({ protocol = string from_port = string to_port = string cidr_blocks = list(string) })) default = [] } resource "aws_security_group" "ec2" { name = "my-sg" description = "SG for ec2" vpc_id = data.aws_vpc.this.id egress { to_port = 0 from_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } ingress { protocol = "tcp" from_port = 22 to_port = 22 cidr_blocks = ["10.0.0.0/8"] } # rdp ingress { protocol = "tcp" from_port = 3389 to_port = 3389 cidr_blocks = ["10.0.0.0/8"] } # additional ingress rules ingress { for_each = var.additional_ingress protocol = each.value.protocol from_port = each.value.from_port to_port = each.value.to_port cidr_blocks = each.value.cidr_blocks } }
运行时出现如下错误:
A reference to "each.value" has been used in a context in which it unavailable, such as when the configuration no longer contains the value in its "for_each" expression. │ Remove this reference to each.value in your configuration to work around this error.
解决方案
错误原因
你遇到的问题是因为不能直接在单个ingress嵌套块中使用for_each,Terraform要求批量生成嵌套块(如安全组的Ingress规则)时,必须使用dynamic块来循环创建多个独立的ingress块。
修改后的完整配置代码
variable "additional_ingress" { type = list(object({ protocol = string # 建议把端口类型改为number,匹配AWS端口的数值类型,避免类型转换问题 from_port = number to_port = number cidr_blocks = list(string) })) default = [] } resource "aws_security_group" "ec2" { name = "my-sg" description = "SG for ec2" vpc_id = data.aws_vpc.this.id egress { to_port = 0 from_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } # 标准SSH规则 ingress { protocol = "tcp" from_port = 22 to_port = 22 cidr_blocks = ["10.0.0.0/8"] } # 标准RDP规则 ingress { protocol = "tcp" from_port = 3389 to_port = 3389 cidr_blocks = ["10.0.0.0/8"] } # 动态生成额外Ingress规则 dynamic "ingress" { # 将列表转为map,用规则的唯一标识作为键,避免列表顺序变动导致资源重建 for_each = { for idx, rule in var.additional_ingress : "${rule.protocol}-${rule.from_port}-${rule.to_port}-${idx}" => rule } content { protocol = ingress.value.protocol from_port = ingress.value.from_port to_port = ingress.value.to_port cidr_blocks = ingress.value.cidr_blocks } } }
关键修改点说明
- 使用
dynamic "ingress"块:这是Terraform批量创建嵌套块的标准方式,通过循环生成多个独立的ingress规则。 - 优化
for_each的键:将列表转换为map时,用协议-起始端口-结束端口-索引作为唯一键,避免因列表元素顺序变化导致安全组规则被重建(如果规则有唯一名称字段,也可以用名称作为键)。 - 端口类型修正:把变量中的
from_port和to_port从string改为number,匹配AWS安全组端口的数值类型,消除潜在的类型转换错误。
内容的提问来源于stack exchange,提问作者LP13
相关产品推荐
相关产品推荐

