Terraform模块调用数据/资源时,变量的正确使用及报错解决
Terraform动态引用AWS IAM策略文档数据源问题解决
问题代码与报错
main.tf
module "SCP-L2-RegionRestriction" { source = "github.com/awsmodulecode/scps.git" scp_name = "SCP-L2-RegionRestriction" }
模块代码(main.tf)
resource "aws_organizations_policy" "SCP-L2-RegionRestriction" { name = var.scp_name content = data.aws_iam_policy_document."${var.scp.name}".json }
模块变量(variables.tf)
variable "scp_name" { description = "Policy name." }
报错信息
╷ │ Error: Invalid attribute name │ │ On .terraform/modules/SCP-L2-RegionRestriction/main.tf line 4: An attribute name is required after a dot. ╵
已定义的数据源
data "aws_iam_policy_document" "scp_fulladmin_deny" { statement { actions = ["*"] resources = ["*"] effect = "Deny" } } data "aws_iam_policy_document" "scp_fulladmin_allow" { statement { actions = ["*"] resources = ["*"] effect = "Allow" } }
问题分析
你尝试用"${var.scp.name}"动态拼接数据源名称的方式在Terraform里是不支持的——Terraform的资源/数据源引用是静态的,不能通过变量拼接名称实现动态调用。另外你的模块变量仅定义了scp_name,不存在var.scp.name这个变量,这也是触发报错的直接原因。
解决方案
要实现根据变量选择不同策略文档的需求,推荐两种常用方法:
方法1:模块内通过变量映射匹配数据源
- 修改模块的
variables.tf,新增变量指定策略类型:
variable "scp_name" { description = "Policy name." } variable "scp_policy_type" { description = "指定要使用的策略文档类型,可选值:scp_fulladmin_deny、scp_fulladmin_allow" type = string validation { condition = contains(["scp_fulladmin_deny", "scp_fulladmin_allow"], var.scp_policy_type) error_message = "必须指定有效的策略类型:scp_fulladmin_deny 或 scp_fulladmin_allow。" } }
- 修改模块的main.tf,用映射表匹配对应数据源:
locals { policy_documents = { scp_fulladmin_deny = data.aws_iam_policy_document.scp_fulladmin_deny.json scp_fulladmin_allow = data.aws_iam_policy_document.scp_fulladmin_allow.json } } resource "aws_organizations_policy" "SCP-L2-RegionRestriction" { name = var.scp_name content = lookup(local.policy_documents, var.scp_policy_type, null) }
- 根模块调用时指定策略类型:
module "SCP-L2-RegionRestriction" { source = "github.com/awsmodulecode/scps.git" scp_name = "SCP-L2-RegionRestriction" scp_policy_type = "scp_fulladmin_deny" # 按需切换类型 }
方法2:直接传入策略文档内容(低耦合更通用)
如果模块不需要依赖内部数据源,直接将策略内容作为变量传入,通用性更强:
- 修改模块的variables.tf:
variable "scp_name" { description = "Policy name." } variable "scp_content" { description = "SCP策略文档的JSON内容" type = string }
- 修改模块的main.tf:
resource "aws_organizations_policy" "SCP-L2-RegionRestriction" { name = var.scp_name content = var.scp_content }
- 根模块调用时传入数据源内容:
module "SCP-L2-RegionRestriction" { source = "github.com/awsmodulecode/scps.git" scp_name = "SCP-L2-RegionRestriction" scp_content = data.aws_iam_policy_document.scp_fulladmin_deny.json }
注意事项
- Terraform不支持动态拼接资源/数据源名称,所有资源引用必须是静态定义的。
- 方法2的模块耦合度更低,无需关心具体策略文档定义,更适合跨场景复用。
内容的提问来源于stack exchange,提问作者Sallyerik
相关产品推荐
相关产品推荐

