Terraform创建多S3桶版本配置报错:需字符串类型值
需要在Terraform中批量创建属性一致(版本控制、所有权等)的S3桶,避免重复代码,且支持后续增删桶不触发全量重建。已通过for_each成功创建桶,但添加版本控制时出现类型错误。
原创建桶的代码
# Create some buckets with the same attributes locals { buckets = { bucket-a = "bucket-a-unique-name" bucket-b = "bucket-b-unique-name" bucket-c = "bucket-c-unique-name" } } # Create the buckets resource "aws_s3_bucket" "bucket_list" { for_each = local.buckets bucket = "name-is-${each.value}" }
成功创建了三个桶:
- name-is-bucket-a-unique-name
- name-is-bucket-b-unique-name
- name-is-bucket-c-unique-name
添加版本控制的代码及报错
resource "aws_s3_bucket_versioning" "versioning" { for_each = local.buckets bucket = aws_s3_bucket.bucket_list[each.key] versioning_configuration { status = "Enabled" } }
报错信息:
│ Error: Incorrect attribute value type
│
│ on buckets.tf line 77, in resource "aws_s3_bucket_versioning" "versioning":
│ 77: bucket = aws_s3_bucket.bucket_list[each.key]
│ ├────────────────
│ │ aws_s3_bucket.bucket_list is object with 3 attributes
│ │ each.key is "bucket-a"
│
│ Inappropriate value for attribute "bucket": string required.
╵
当前环境:AWS Provider 4.6.7,Terraform 1.5.3。此前尝试count元参数,会导致增删桶时所有资源全量重建,不符合需求。
1. 修复版本控制资源的引用错误
报错核心原因是aws_s3_bucket.bucket_list[each.key]返回的是桶的资源对象,而aws_s3_bucket_versioning的bucket参数需要的是桶名称的字符串类型值。只需引用资源对象的bucket或id属性即可:
resource "aws_s3_bucket_versioning" "versioning" { for_each = local.buckets # 两种写法等价,均返回桶名称字符串 bucket = aws_s3_bucket.bucket_list[each.key].bucket # 或 bucket = aws_s3_bucket.bucket_list[each.key].id versioning_configuration { status = "Enabled" } }
2. 优化方案:用模块封装通用属性
如果后续需要添加更多通用配置(如所有权、加密、生命周期规则等),可以将S3桶的通用逻辑封装为Terraform模块,通过for_each调用模块批量创建,进一步提升代码复用性:
模块文件(modules/s3_bucket/main.tf)
resource "aws_s3_bucket" "this" { bucket = var.bucket_name } resource "aws_s3_bucket_versioning" "this" { bucket = aws_s3_bucket.this.bucket versioning_configuration { status = var.versioning_status } } # 示例:添加所有权控制配置 resource "aws_s3_bucket_ownership_controls" "this" { bucket = aws_s3_bucket.this.bucket rule { object_ownership = var.object_ownership } }
模块变量文件(modules/s3_bucket/variables.tf)
variable "bucket_name" { type = string description = "Name of the S3 bucket" } variable "versioning_status" { type = string description = "Versioning status for the bucket" default = "Enabled" } variable "object_ownership" { type = string description = "Object ownership setting for the bucket" default = "BucketOwnerEnforced" }
主调用文件
locals { buckets = { bucket-a = "name-is-bucket-a-unique-name" bucket-b = "name-is-bucket-b-unique-name" bucket-c = "name-is-bucket-c-unique-name" } } module "s3_buckets" { for_each = local.buckets source = "./modules/s3_bucket" bucket_name = each.value }
3. 保持for_each的优势
使用for_each而非count的核心价值在于:增删桶时只会对变更的桶执行创建/销毁操作,已存在的桶不受影响,彻底避免全量重建。后续只需维护local.buckets映射即可轻松管理桶的生命周期。
内容的提问来源于stack exchange,提问作者Joe

