如何在Terraform的tuple(object)类型变量默认值中引用资源?
问题描述
部署多台EC2实例时,定义了tuple(object)类型的Terraform变量configuration,当前vpc_security_group_ids采用硬编码安全组ID的方式,不够优雅。尝试使用local值或直接引用安全组资源ID时,触发「Variables may not be used here」错误。
变量定义:
variable "configuration" { #description = "The total configuration, List of Objects/Dictionary" default = [ { "application_name" : "GritfyApp-dev", "ami" : "ami-0263e4deb427da90e", "no_of_instances" : "2", "instance_type" : "t2.medium", "subnet_id" : "subnet-0dd2853d1445a9990", "vpc_security_group_ids" : ["sg-00e9778636a7aee5e","sg-082e93cadbd35fd8b"] # "vpc_security_group_ids" : [aws_security_group.ssh-sg.id] }, { "application_name" : "ssh-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "1", "subnet_id" : "subnet-0dd2853d1445a9990", "vpc_security_group_ids" : ["sg-00e9778636a7aee5e","sg-082e93cadbd35fd8b"] # "vpc_security_group_ids" : [aws_security_group.ssh-sg.id] }, { "application_name" : "OpsGrit-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "3", "subnet_id" : "subnet-0dd2853d1445a9990", "vpc_security_group_ids" : ["sg-00e9778636a7aee5e","sg-082e93cadbd35fd8b"] # "vpc_security_group_ids" : [aws_security_group.ssh-sg.id] } ] }
报错信息:
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now. root@Will-T-PC:/mnt/c/terraform-leaning-will/Expressions/deploy-multiple-ec2-for_each-2# terraform plan ╷ │ Error: Variables not allowed │ │ on variables.tf line 17, in variable "configuration": │ 17: "vpc_security_group_ids" : local.target_sg │ │ Variables may not be used here. ╵
原因分析
Terraform的变量默认值只能是静态常量,无法引用local值、资源属性或其他变量。这是因为变量初始化发生在配置解析的最早期阶段,此时Terraform还未构建资源依赖关系,无法计算动态值。
解决方法
方法一:用Local值合并静态配置与动态安全组ID
将变量中的静态配置与动态的安全组ID分离,通过local值完成合并:
- 调整变量定义,移除硬编码的安全组ID:
variable "configuration" { default = [ { "application_name" : "GritfyApp-dev", "ami" : "ami-0263e4deb427da90e", "no_of_instances" : "2", "instance_type" : "t2.medium", "subnet_id" : "subnet-0dd2853d1445a9990" }, { "application_name" : "ssh-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "1", "subnet_id" : "subnet-0dd2853d1445a9990" }, { "application_name" : "OpsGrit-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "3", "subnet_id" : "subnet-0dd2853d1445a9990" } ] }
- 定义安全组资源(示例配置):
resource "aws_security_group" "ssh_sg" { name = "ssh-sg" description = "Allow SSH access" vpc_id = "your-vpc-id" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "app_sg" { name = "app-sg" description = "Allow app traffic" vpc_id = "your-vpc-id" // 按需配置 ingress/egress 规则 }
- 通过local合并配置与动态安全组ID:
locals { ec2_configurations = [ for cfg in var.configuration : merge(cfg, { // 根据实例名称分配对应安全组 vpc_security_group_ids = cfg.application_name == "ssh-dev" ? [aws_security_group.ssh_sg.id] : [aws_security_group.ssh_sg.id, aws_security_group.app_sg.id] }) ] }
- 创建EC2实例时引用local中的配置:
resource "aws_instance" "ec2_instances" { for_each = { for idx, cfg in local.ec2_configurations : "${cfg.application_name}-${idx}" => cfg } ami = each.value.ami instance_type = each.value.instance_type subnet_id = each.value.subnet_id vpc_security_group_ids = each.value.vpc_security_group_ids tags = { Name = each.value.application_name } }
方法二:用标识映射实现多实例多安全组
如果不同实例需要绑定不同安全组,可在变量中用标识代替硬编码ID,再通过local映射到实际资源ID:
- 修改变量,用安全组标识替代ID:
variable "configuration" { default = [ { "application_name" : "GritfyApp-dev", "ami" : "ami-0263e4deb427da90e", "no_of_instances" : "2", "instance_type" : "t2.medium", "subnet_id" : "subnet-0dd2853d1445a9990", "security_group_tags" : ["ssh-sg", "app-sg"] }, { "application_name" : "ssh-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "1", "subnet_id" : "subnet-0dd2853d1445a9990", "security_group_tags" : ["ssh-sg"] }, { "application_name" : "OpsGrit-dev", "ami" : "ami-0747bdcabd34c712a", "instance_type" : "t3.micro", "no_of_instances" : "3", "subnet_id" : "subnet-0dd2853d1445a9990", "security_group_tags" : ["ssh-sg", "app-sg"] } ] }
- 创建安全组标识到ID的映射:
locals { sg_id_map = { "ssh-sg" = aws_security_group.ssh_sg.id, "app-sg" = aws_security_group.app_sg.id } ec2_configurations = [ for cfg in var.configuration : merge(cfg, { vpc_security_group_ids = [for tag in cfg.security_group_tags : local.sg_id_map[tag]] }) ] }
- 后续创建EC2实例的逻辑和方法一一致,引用
local.ec2_configurations即可。
内容的提问来源于stack exchange,提问作者Wei Yu
相关产品推荐
相关产品推荐

