如何正确实现Terraform嵌套for循环以创建AWS路由?
Terraform 路由资源遍历配置问题修复
问题场景
需遍历private和public两种路由类型,同时为每种路由下的每个cidr_block创建路由资源,但原代码运行报错。
原代码
locals { routes = { private = { route_table_ids = module.vpc.private_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } public = { route_table_ids = module.vpc.public_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } } } resource "aws_route" "vpc_route" { for_each = { for route in local.routes : for cidr in route.cidr_blocks : "${route}-${cidr}" => { route_table_id = route.route_table_ids destination_cidr_block = cidr } } route_table_id = each.value.route_table_id destination_cidr_block = each.value.destination_cidr_block gateway_id = module.vpc.vgw_id }
报错信息
╷ │ Error: Invalid 'for' expression │ │ on routes.tf line 17, in resource "aws_route" "vpc_meta_route": │ 15: for_each = { │ 16: for route in local.routes : │ 17: for cidr in route.cidr_blocks : "${route}-${cidr}" => { │ 18: route_table_id = route.route_table_ids │ 19: destination_cidr_block = cidr │ 20: } │ 21: } │ │ Key expression is required when building an object. ╵ ╷ │ Error: Invalid 'for' expression │ │ on routes.tf line 17, in resource "aws_route" "vpc_meta_route": │ 15: for_each = { │ 16: for route in local.routes : │ 17: for cidr in route.cidr_blocks : "${route}-${cidr}" => { │ │ Extra characters after the end of the 'for' expression. ╵ FAIL
问题分析
- 嵌套
for循环语法错误:Terraform构建映射的嵌套for表达式,需要明确外层循环的键值处理逻辑,原写法缺少外层键定义,格式不符合规范。 - 路由表ID类型不匹配:
module.vpc.private_route_table_ids通常是列表类型(包含多个路由表ID),但aws_route的route_table_id参数要求单个字符串值,直接赋值会报错。
修复后的代码
方案1:通过本地值扁平化配置
先将多层嵌套的路由配置扁平化,再转换为for_each可用的映射:
locals { routes = { private = { route_table_ids = module.vpc.private_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } public = { route_table_ids = module.vpc.public_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } } # 扁平化路由配置:路由类型 + 单个路由表ID + 单个CIDR块 flattened_routes = flatten([ for route_type, config in local.routes : [ for rt_id in config.route_table_ids : [ for cidr in config.cidr_blocks : { route_type = route_type rt_id = rt_id cidr = cidr } ] ] ]) # 生成唯一键的映射,满足for_each要求 route_map = { for route in local.flattened_routes : "${route.route_type}-${route.rt_id}-${route.cidr}" => route } } resource "aws_route" "vpc_route" { for_each = local.route_map route_table_id = each.value.rt_id destination_cidr_block = each.value.cidr gateway_id = module.vpc.vgw_id }
方案2:直接在for_each中处理
无需额外本地值,直接在for_each表达式内完成扁平化:
locals { routes = { private = { route_table_ids = module.vpc.private_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } public = { route_table_ids = module.vpc.public_route_table_ids cidr_blocks = ["10.1.0.0/16", "10.2.0.0/16", "10.5.0.0/16"] } } } resource "aws_route" "vpc_route" { for_each = { for route in flatten([ for route_type, config in local.routes : [ for rt_id in config.route_table_ids : [ for cidr in config.cidr_blocks : { key = "${route_type}-${rt_id}-${cidr}" rt_id = rt_id cidr = cidr } ] ] ]) : route.key => route } route_table_id = each.value.rt_id destination_cidr_block = each.value.cidr gateway_id = module.vpc.vgw_id }
内容的提问来源于stack exchange,提问作者João Amaro
相关产品推荐
相关产品推荐

