如何用Terraform遍历JSON数组创建AWS IAM用户?
解决Terraform遍历JSON用户列表创建IAM用户的语法错误
问题场景
我有一个包含用户和组列表的JSON文件(数组结构),想要通过Terraform在AWS IAM中批量创建用户,但执行terraform plan时遇到以下错误:
Error: Error in function call │ │ on locals.tf line 3, in locals: │ 3: json_data = merge([for f in local.json_files : jsondecode(file("${path.module}/input/${f}"))]...) │ ├──────────────── │ │ local.json_files is set of string with 1 element │ │ path.module is "." │ │ Call to function "merge" failed: arguments must be maps or objects, got "tuple".
JSON文件示例(偏好的原结构):
[ { "name": "user1", "groups": ["Admins", "DevOps"], "policies": [] }, { "name": "user2", "groups": ["DevOps"], "policies": [] } ]
原Terraform代码:
locals { json_files = fileset("${path.module}/input/", "*.json") json_data = merge([for f in local.json_files : jsondecode(file("${path.module}/input/${f}"))]...) } resource "aws_iam_user" "create_new_users" { for_each = local.json_data name = each.name }
注:我曾将JSON改为键值对结构(如下)让代码正常运行,但更希望保留原数组结构:
{ "user1": {"groups": ["Admins","DevOps"],"policies": []}, "user2": {"groups": ["DevOps"],"policies": []} }
对应的资源代码:
resource "aws_iam_user" "create_new_users" { for_each = local.json_data name = each.key }
解决方案
错误原因
merge函数仅接受映射(map)或对象(object)作为参数,但原JSON解析后得到的是元组(tuple/数组),直接传入merge会触发报错。同时Terraform的for_each仅支持映射或集合类型,因此需要将数组转换为以用户名为键的映射,才能满足使用要求。
修改后的Terraform代码
1. 调整局部变量定义
读取JSON数组并转换为以用户名为键的映射:
locals { json_files = fileset("${path.module}/input/", "*.json") # 读取所有JSON文件并合并为一个用户数组(支持多文件场景) user_list = flatten([ for f in local.json_files : jsondecode(file("${path.module}/input/${f}")) ]) # 将数组转换为以用户名为键的映射 user_map = { for user in local.user_list : user.name => user } }
flatten用于处理多JSON文件场景,将多个文件的数组合并为一个大数组for user in local.user_list : user.name => user遍历用户数组,生成键为用户名、值为用户完整对象的映射
2. 更新IAM用户资源
使用转换后的user_map作为for_each的数据源:
resource "aws_iam_user" "create_new_users" { for_each = local.user_map name = each.key # 也可以用 each.value.name,结果一致 }
3. 可选:批量关联用户到IAM组
如果需要同时将用户加入指定组,可以添加以下资源:
resource "aws_iam_user_group_membership" "user_groups" { for_each = local.user_map user = each.key groups = each.value.groups }
说明
- 原修改JSON结构的方案可行,是因为直接生成了Terraform
for_each支持的映射类型;而保留原数组结构的关键是通过Terraform的for表达式完成数组到映射的转换。 - 需确保JSON中每个用户的
name字段唯一,否则转换映射时会出现键冲突,Terraform会直接报错提示重复键。
内容的提问来源于stack exchange,提问作者Stephan Du Toit
相关产品推荐
相关产品推荐

