Terraform动态块Map迭代报错:无法使用字符串Map作为可迭代集合
解决Terraform dynamic块迭代字符串Map报错问题
问题场景
尝试通过Terraform配置AWS MQ Broker的用户列表,操作流程如下:
- 在Vault中存储JSON格式的用户名/密码:
{ "user1": "longPassword1", "user2amq": "longPassword2", "user3": "longPassword3" }
- 声明Vault数据源拉取凭据:
data "vault_kv_secret_v2" "all_clients" { provider = my.vault.provider mount = "credentials/aws/amq" name = "dev/clients" }
- 将JSON转为Map类型:
locals { all_clients = tomap(jsondecode(data.vault_kv_secret_v2.all_clients.data.client_list)) }
- 通过dynamic块迭代Map生成用户:
dynamic "user" { for_each = local.all_clients content { username = each.key password = each.value console_access = "false" groups = ["users"] } }
执行terraform apply时报错:
│ on modules/amq/amq.tf line 66, in resource "aws_mq_broker" "myproject": │ 66: for_each = local.all_clients │ │ Cannot use a map of string value in for_each. An iterable collection is │ required.
已验证terraform output -json all_clients能正常输出结构,排除数据源解析问题;同时确认AWS AmazonMQ限制:用户名不支持邮箱格式,密码需12-250字符。
解决方案
方案1:将字符串Map转换为对象列表
Terraform的dynamic块对迭代的集合类型有隐性要求,将map(string)转换为包含键值对的对象列表即可解决:
locals { all_clients = tomap(jsondecode(data.vault_kv_secret_v2.all_clients.data.client_list)) # 转换为包含用户名、密码的对象列表 client_users = [for username, password in local.all_clients : { username = username password = password }] }
修改dynamic块迭代这个对象列表:
dynamic "user" { for_each = local.client_users content { username = user.value.username password = user.value.password console_access = "false" groups = ["users"] } }
方案2:迭代Map的键集合
直接将Map的键转换为Set类型进行迭代,再通过键取值:
dynamic "user" { for_each = toset(keys(local.all_clients)) content { username = user.key password = local.all_clients[user.key] console_access = "false" groups = ["users"] } }
原因说明
Terraform 1.3.5中,虽然map(string)本身是可迭代集合,但AWS MQ Broker的user嵌套块对dynamic迭代的元素类型有隐性要求,仅接受结构化的对象集合或键集合。上述两种方法均能将原字符串Map转换为符合要求的可迭代类型,解决报错问题。
内容的提问来源于stack exchange,提问作者рüффп
相关产品推荐
相关产品推荐

