Terraform动态生成含IAM角色ARN的JSON模板报错求助
问题:Terraform动态生成含IAM角色ARN的JSON对象
操作步骤及报错情况
- 获取匹配的IAM角色列表:
data "aws_iam_roles" "matching_roles" { for_each = toset(["role-prefix1-.*", "ecs-role.*"]) name_regex = each.value }
- 收集所有角色ARN到列表:
locals { flat_arns = flatten([ for key, role_set in data.aws_iam_roles.matching_roles : role_set.arns ]) }
- 尝试用template_file生成JSON模板的两种错误尝试:
第一种尝试及错误
代码:
data "template_file" "dynamic_roles_os" { template = <<EOF { "roles": [ {% for role in roles %} { "role_name": "all_access", "role_mapping_payload": { "backend_roles": [ "${role}" ], "hosts": [], "users": [] } }{% if not loop.last %},{% endif %} {% endfor %} ] } EOF vars = { roles = local.flat_arns } } resource "local_file" "backend_roles_json" { content = data.template_file.dynamic_roles_os.rendered filename = "${path.module}/backend_roles.json" }
错误信息:
╷ │ Error: Invalid reference │ │ on dynamic-roles.tf line 266, in data "template_file" "dynamic_roles_os": │ 266: "${role}" │ │ A reference to a resource type must be followed by at least one attribute │ access, specifying the resource name. ╵ Operation failed: failed running terraform plan (exit 1)
第二种尝试及错误
代码:
locals { matching_roles = flatten([ for key, role_set in data.aws_iam_roles.matching_roles : [ for arn in role_set.arns : { arn = arn } ] ]) } data "template_file" "dynamic_roles_os" { template = <<EOF { "roles": [ {% for role in roles %} { "role_name": "all_access", "role_mapping_payload": { "backend_roles": [ "${role.arn}" ], "hosts": [], "users": [] } }{% if not loop.last %},{% endif %} {% endfor %} ] } EOF vars = { roles = local.matching_roles } } resource "local_file" "backend_roles_json" { content = data.template_file.dynamic_roles_os.rendered filename = "${path.module}/backend_roles.json" }
错误信息:
│ Error: Reference to undeclared resource │ │ on dynamic-roles.tf line 268, in data "template_file" "dynamic_roles_os": │ 268: "${role.arn}" │ │ A managed resource "role" "arn" has not been declared in the root module. ╵ Operation failed: failed running terraform plan (exit 1)
解决方案
问题根源在于**template_file使用Go模板语法,而非Terraform的插值语法${}**,你错误地用了Terraform的变量引用方式,导致Terraform将模板内的${role}解析为资源引用而非模板变量。
更推荐的做法是直接使用Terraform内置的jsonencode函数,完全避免模板语法的混淆,代码如下:
方法1:用jsonencode直接生成JSON
data "aws_iam_roles" "matching_roles" { for_each = toset(["role-prefix1-.*", "ecs-role.*"]) name_regex = each.value } locals { flat_arns = flatten([ for key, role_set in data.aws_iam_roles.matching_roles : role_set.arns ]) # 构造JSON结构的原生Terraform数据结构 role_mappings = { roles = [ for arn in local.flat_arns : { role_name = "all_access" role_mapping_payload = { backend_roles = [arn] hosts = [] users = [] } } ] } # 直接编码为JSON字符串 role_mappings_json = jsonencode(local.role_mappings) } resource "local_file" "backend_roles_json" { content = local.role_mappings_json filename = "${path.module}/backend_roles.json" }
方法2:修正template_file的模板语法(不推荐,template_file已被标记为弃用)
如果一定要用template_file,需要改用Go模板的变量引用语法{{ .role }},同时注意循环和变量传递的正确写法:
data "aws_iam_roles" "matching_roles" { for_each = toset(["role-prefix1-.*", "ecs-role.*"]) name_regex = each.value } locals { flat_arns = flatten([ for key, role_set in data.aws_iam_roles.matching_roles : role_set.arns ]) } data "template_file" "dynamic_roles_os" { template = <<EOF { "roles": [ {{ range $index, $role := .roles }} { "role_name": "all_access", "role_mapping_payload": { "backend_roles": [ "{{ $role }}" ], "hosts": [], "users": [] } }{{ if ne $index (sub (len .roles) 1) }},{{ end }} {{ end }} ] } EOF vars = { roles = local.flat_arns } } resource "local_file" "backend_roles_json" { content = data.template_file.dynamic_roles_os.rendered filename = "${path.module}/backend_roles.json" }
说明
jsonencode是Terraform官方推荐的生成JSON的方式,它会自动处理转义、格式等问题,避免手动写模板的语法错误。template_file已被官方标记为弃用,建议使用templatefile函数(小写的函数,非数据源)替代,但依然不如jsonencode直接高效。
内容的提问来源于stack exchange,提问作者Jenobi
相关产品推荐
相关产品推荐

