Terraform配置安全组Ingress规则时lookup子网CIDR报错问题
问题:Terraform调用lookup函数报错:inputMap参数无效
场景重现
尝试将Ingress规则列表传递给aws_security_group资源,规则以map列表形式定义:
ingress = [ { "from_port": 443, "to_port": 443, "protocol": "tcp", "subnet_roles": [ "web" ] }, { "from_port": 3389, "to_port": 3389, "protocol": "tcp", "subnet_roles": [ "private","management" ] } ]
在模块中通过subnet_roles查找对应CIDR块,编写代码如下:
ingress_rules = [ for rule in each.value.rules.ingress : merge(rule, { cidr_blocks = [ for role in rule.subnet_roles : lookup(module.aws_vpc.subnets_by_role[role], "cidr_block", null) ] } )]
执行时报错:
"Invalid value for "inputMap" parameter: lookup() requires a map as the first argument."
其中subnets_by_role通过以下方式构建:
subnets_by_role = merge( { for subnet in aws_subnet.public : subnet.tags.subnet_role => subnet... }, { for subnet in aws_subnet.private : subnet.tags.subnet_role => subnet... } )
问题原因
- 同角色子网覆盖:使用
merge结合subnet...展开语法时,若多个子网标记了相同的subnet_role,后定义的子网属性会覆盖前面的;若某个role不存在(比如示例中的management),module.aws_vpc.subnets_by_role[role]会返回null,而lookup要求第一个参数必须是map,null不符合要求。 - 展开语法误用:
subnet...会将子网对象的属性展开为键值对,但实际需要保留子网对象本身作为map值,而非展开后的属性集合。
解决方案
步骤1:修正subnets_by_role的构建逻辑
改用groupby将同角色的子网归类为列表,避免覆盖问题:
subnets_by_role = { for role, subnets in groupby(concat(aws_subnet.public, aws_subnet.private), "tags.subnet_role") : role => subnets }
此时每个role对应的是相同角色的子网对象列表,而非单个子网。
步骤2:调整Ingress规则的CIDR查找逻辑
遍历每个角色对应的子网列表,提取CIDR块并扁平化:
ingress_rules = [ for rule in each.value.rules.ingress : merge(rule, { cidr_blocks = flatten([ for role in rule.subnet_roles : [for subnet in lookup(module.aws_vpc.subnets_by_role, role, []) : subnet.cidr_block] ]) }) ]
- 使用
lookup(module.aws_vpc.subnets_by_role, role, [])处理不存在的角色,返回空列表而非null - 嵌套遍历提取每个子网的
cidr_block,再用flatten将二维列表转为一维,符合aws_security_group的cidr_blocks参数格式要求
内容的提问来源于stack exchange,提问作者bitbucket
相关产品推荐
相关产品推荐

