Terraform中如何迭代长度不同的Map元素生成IAM策略资源
Terraform配置报错解决:多列表迭代生成S3资源ARN
报错信息
Invalid value for "args" parameter: argument 3 has length 1, which is inconsistent with argument 2 of length 3
中文翻译:参数"args"值无效:参数3长度为1,与长度为3的参数2不匹配
原Terraform配置
locals { environment_map = { prd = ["prd"] nonprd = ["dev", "qa", "stg"] } bucket_name = "test-bucket" account = "Prod" consumers_config = { client1 = { provider_url = "www.google.com/abc/" source_id = ["1001"] } } client_map = merge([ for consumer, consumer_details in local.consumers_config : { for env, env_details in local.environment_map : "${consumer}_${env}" => { env = env_details source_id_list = consumer_details["source_id"] provider_url = consumer_details["provider_url"] audience_id = "URN://${consumer}_${local.account_type}_AWS_${local.account}" } }]...) } data "aws_iam_policy_document" "read_policy" { for_each = var.client_specific_iam_roles ? local.client_map : {} statement { effect = "Allow" actions = [ "s3:GetObject", "s3:GetObjectAttributes", "s3:GetObjectVersion", "s3:GetObjectVersionAttributes" ] resources = concat(formatlist("arn:aws:s3:::%s/%s/test/test_json/*/source_id=%s/*", local.bucket_name,lookup(each.value, "env"), lookup(each.value, "source_id"))) } }
问题说明
当前配置中,env字段是多元素列表(比如nonprd对应["dev","qa","stg"]),source_id_list也是多元素列表,需要同时迭代这两个列表生成所有组合的S3资源ARN。但直接使用formatlist会因为两个列表长度不匹配报错,目前将source_id_list改为单个字符串能临时解决,但需求要求支持多个source_id,如何实现?
解决方案
方案一:提前拆分所有组合到client_map
核心思路是在生成client_map时,直接遍历env和source_id的所有笛卡尔积组合,将每个组合作为单独的条目,避免后续处理时的列表长度不匹配问题。
修改后的client_map代码:
client_map = merge([ for consumer, consumer_details in local.consumers_config : { for env, env_details in local.environment_map : { for source_id in consumer_details["source_id"] : "${consumer}_${env}_${source_id}" => { env = env_details source_id = source_id provider_url = consumer_details["provider_url"] audience_id = "URN://${consumer}_${local.account_type}_AWS_${local.account}" } } }]...)
对应的aws_iam_policy_document调整为:
data "aws_iam_policy_document" "read_policy" { for_each = var.client_specific_iam_roles ? local.client_map : {} statement { effect = "Allow" actions = [ "s3:GetObject", "s3:GetObjectAttributes", "s3:GetObjectVersion", "s3:GetObjectVersionAttributes" ] resources = [ format("arn:aws:s3:::%s/%s/test/test_json/*/source_id=%s/*", local.bucket_name, each.value.env, each.value.source_id) ] } }
此方案适合需要为每个env+source_id组合单独配置额外属性的场景。
方案二:在生成Policy时动态生成组合
如果不想修改原有client_map结构,可以在生成resources时,通过嵌套for表达式生成env和source_id的所有组合,再用flatten将嵌套列表转为一维列表。
修改后的resources字段代码:
resources = flatten([ for env in each.value.env : [ for source_id in each.value.source_id_list : format("arn:aws:s3:::%s/%s/test/test_json/*/source_id=%s/*", local.bucket_name, env, source_id) ] ])
此方案无需调整client_map,直接在Policy生成阶段处理组合逻辑,适合原有结构需要保留的场景。
内容的提问来源于stack exchange,提问作者bharath
相关产品推荐
相关产品推荐

