AWS与Terraform:遍历远程状态配置安全组Ingress的语法问题
问题描述
我在配置Terraform时遇到语法问题,通过以下代码读取S3中的Terraform远程状态:
data "terraform_remote_state" vpc { backend = "s3" config = { region = "eu-west-1" bucket = "some-terraform-bucket" key = "some-vpc-state.tfstate" } }
该远程状态包含类型为list(string)的private_subnets_cidr_blocks,值如下:
private_subnets_cidr_blocks value 0 "20.10.8.0/24" 1 "20.10.9.0/24" 2 "20.10.10.0/24" type 0 "list" 1 "string"
我尝试将这些CIDR块添加到安全组的Ingress规则中,使用了如下配置:
module "security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 5.0" name = "${var.name}-${var.environment}-redis" description = "Redis example security group" vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id count = length(data.terraform_remote_state.vpc.outputs.elasticache_subnets_cidr_blocks) # ingress ingress_with_cidr_blocks = [ { for_each = data.terraform_remote_state.vpc.outputs.private_subnets_cidr_blocks from_port = 6379 to_port = 6379 protocol = "tcp" description = "Redis access from within VPC" cidir_blocks = [each.value] } ] tags = local.default_tags }
但出现错误:
The given value is not suitable for module.security_group.var.ingress_with_cidr_blocks declared at .terraform/modules/security_group/variables.tf:85,1-36: element 0: element "cidir_blocks": string required.
我期望将CIDR块拼接为如下格式的字符串供Terraform处理:
cidr_blocks = "20.10.8.0/24, 20.10.9.0/24,20.10.10.0/24"
解决方案
错误原因分析
for_each使用位置错误:不能在ingress_with_cidr_blocks的单个对象内部使用for_each,需用Terraform列表推导式生成规则列表。- 拼写错误:配置中写的
cidir_blocks是笔误,正确参数名应为cidr_blocks,这是报错的直接原因之一。 - 格式不匹配:该安全组模块的
cidr_blocks支持字符串(逗号分隔)或列表类型,原写法把单个CIDR放入列表,叠加拼写错误导致类型不兼容。
正确实现方式
写法1:合并所有CIDR为单条规则(逗号分隔字符串)
用join函数将列表拼接成逗号分隔的字符串,创建一条覆盖所有私有子网的Ingress规则:
module "security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 5.0" name = "${var.name}-${var.environment}-redis" description = "Redis example security group" vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id ingress_with_cidr_blocks = [ { from_port = 6379 to_port = 6379 protocol = "tcp" description = "Redis access from within VPC" cidr_blocks = join(", ", data.terraform_remote_state.vpc.outputs.private_subnets_cidr_blocks) } ] tags = local.default_tags }
写法2:为每个CIDR创建单独Ingress规则
如果需要为每个子网CIDR生成独立规则,使用列表推导式:
module "security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 5.0" name = "${var.name}-${var.environment}-redis" description = "Redis example security group" vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id ingress_with_cidr_blocks = [ for cidr in data.terraform_remote_state.vpc.outputs.private_subnets_cidr_blocks : { from_port = 6379 to_port = 6379 protocol = "tcp" description = "Redis access from ${cidr}" cidr_blocks = cidr # 直接用单个字符串,或用列表[cidr]也可,模块均支持 } ] tags = local.default_tags }
额外说明
- 移除了不必要的
count参数,只需创建一个安全组,内部包含对应Ingress规则即可。 - 该安全组模块的
ingress_with_cidr_blocks参数中,cidr_blocks同时支持字符串(逗号分隔)和列表类型,两种写法都能被正确解析。
内容的提问来源于stack exchange,提问作者Ric_Harvey
相关产品推荐
相关产品推荐

