如何通过存储资源名的变量动态引用Terraform的data资源
报错原因
Terraform 不支持直接通过字符串插值拼接的方式动态引用资源/数据源的标识符,你写的iam_policy_document = data.aws_iam_policy_document.${var.s3_bucket_names[count.index]}.json属于非法语法:${}插值只能用于属性值的定义场景,不能用于拼接资源的名称标识,Terraform需要在静态解析阶段就确定资源引用地址,不支持运行时动态生成资源标识符。
解决方案
方案1:手动映射所有数据源到Map(适合无法调整现有data资源定义的场景)
先通过局部变量把已声明的所有iam policy数据源组装成键值对映射,再通过变量索引取值:
# 新增局部变量定义数据源映射 locals { s3_policy_doc_map = { "1_s3_access_policy" = data.aws_iam_policy_document.1_s3_access_policy.json "2_s3_access_policy" = data.aws_iam_policy_document.2_s3_access_policy.json "3_s3_access_policy" = data.aws_iam_policy_document.3_s3_access_policy.json } } module "platform-cloud" { source = "./module" count = length(var.s3_bucket_names) bucket_name = var.s3_bucket_names[count.index] sse_algorithm = "aws:kms" # 直接从映射中按key取值 iam_policy_document = local.s3_policy_doc_map[var.s3_bucket_names[count.index]] }
方案2:动态生成data数据源(推荐,减少冗余代码)
你当前写了多份重复的aws_iam_policy_document定义,完全可以直接用count动态生成数据源,不需要单独声明多份:
# 删掉原来的N份单独的data定义,统一用count动态生成 data "aws_iam_policy_document" "s3_access_policy" { count = length(var.s3_bucket_names) statement { effect = "Allow" actions = [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject", ] resources = [ "arn:aws:s3:::${var.s3_bucket_names[count.index]}/*", "arn:aws:s3:::${var.s3_bucket_names[count.index]}", ] principals { type = "AWS" identifiers = ["arn:aws:iam::67435677645:user/d2c-user-us-west-1"] } } } module "platform-cloud" { source = "./module" count = length(var.s3_bucket_names) bucket_name = var.s3_bucket_names[count.index] sse_algorithm = "aws:kms" # 按索引直接取对应动态生成的数据源 iam_policy_document = data.aws_iam_policy_document.s3_access_policy[count.index].json }
这种方案后续新增bucket只需要往var.s3_bucket_names列表中加元素即可,不需要修改其他代码,维护成本更低。
内容的提问来源于stack exchange,提问作者Sallyerik
相关产品推荐
相关产品推荐

