You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform动态生成含IAM角色ARN的JSON模板报错求助

问题:Terraform动态生成含IAM角色ARN的JSON对象

操作步骤及报错情况

  1. 获取匹配的IAM角色列表:
data "aws_iam_roles" "matching_roles" {
  for_each   = toset(["role-prefix1-.*", "ecs-role.*"])
  name_regex = each.value
}
  1. 收集所有角色ARN到列表:
locals {
  flat_arns = flatten([
    for key, role_set in data.aws_iam_roles.matching_roles : role_set.arns
  ])
}
  1. 尝试用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:05:21