Terraform S3 Bucket加密配置反复移除再添加问题求助
每次执行terraform apply后,S3桶的服务器端加密配置会被移除,再次执行apply又会重新添加。无代码变更时执行terraform plan,会显示要移除aws_s3_bucket.terraform-state内的server_side_encryption_configuration块,下次执行则会添加回来。
Terraform Plan 输出
# aws_s3_bucket.terraform-state will be updated in-place ~ resource "aws_s3_bucket" "terraform-state" { id = "company-terraform-state" tags = {} # (11 unchanged attributes hidden) - server_side_encryption_configuration { - rule { - bucket_key_enabled = false -> null - apply_server_side_encryption_by_default { - kms_master_key_id = "arn:aws:kms:us-east-1:123456789012:key/Random-GUID-ABCD-1234" -> null - sse_algorithm = "aws:kms" -> null } } } # (1 unchanged block hidden) }
相关配置文件(state.tf)
// This file is based on the writtings here: https://technology.doximity.com/articles/terraform-s3-backend-best-practices terraform { backend "s3" { bucket = "company-terraform-state" key = "state/terraform.tfstate" region = "us-east-1" encrypt = true kms_key_id = "alias/terraform-bucket-key" dynamodb_table = "terraform-state" } } // The backend configuration above is added after the state s3 bucket is created with the rest of the file below resource "aws_kms_key" "terraform-bucket-key" { description = "This key is used to encrypt bucket objects for terraform state" deletion_window_in_days = 10 enable_key_rotation = true } resource "aws_kms_alias" "key-alias" { name = "alias/terraform-bucket-key" target_key_id = aws_kms_key.terraform-bucket-key.key_id } resource "aws_s3_bucket" "terraform-state" { bucket = "company-terraform-state" } resource "aws_s3_bucket_server_side_encryption_configuration" "encryption-config" { bucket = aws_s3_bucket.terraform-state.id rule { apply_server_side_encryption_by_default { kms_master_key_id = aws_kms_key.terraform-bucket-key.arn sse_algorithm = "aws:kms" } } } resource "aws_s3_bucket_versioning" "versioning" { bucket = aws_s3_bucket.terraform-state.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_acl" "acl" { bucket = aws_s3_bucket.terraform-state.id acl = "private" } resource "aws_s3_bucket_public_access_block" "block" { bucket = aws_s3_bucket.terraform-state.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } // This table exists to prevent multiple team members from modifying the state file at the same time resource "aws_dynamodb_table" "terraform-state" { name = "terraform-state" read_capacity = 20 write_capacity = 20 hash_key = "LockID" attribute { name = "LockID" type = "S" } }
解决方案
这个问题的根源是Terraform的AWS Provider会读取S3桶的实际属性(包括加密配置)到状态中,但你的代码里aws_s3_bucket资源未定义server_side_encryption_configuration块,同时又用独立的aws_s3_bucket_server_side_encryption_configuration资源管理加密,导致Terraform每次plan时都会认为该块是多余的要移除,而实际API中的配置由独立资源维护,下次plan又会被读取回来,形成循环变更。
有两种可行的解决方法:
方法1:在S3桶资源中声明空的加密配置块
修改aws_s3_bucket.terraform-state资源,添加空的server_side_encryption_configuration块,明确告诉Terraform忽略该属性的状态差异,由独立资源负责管理:
resource "aws_s3_bucket" "terraform-state" { bucket = "company-terraform-state" # 显式声明空块,避免Terraform检测到API返回的加密配置后试图移除 server_side_encryption_configuration {} }
方法2:将加密配置内嵌到S3桶资源中
删除独立的aws_s3_bucket_server_side_encryption_configuration.encryption-config资源,把加密配置直接写入aws_s3_bucket资源内部:
resource "aws_s3_bucket" "terraform-state" { bucket = "company-terraform-state" server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { kms_master_key_id = aws_kms_key.terraform-bucket-key.arn sse_algorithm = "aws:kms" } } } }
两种方法都能解决循环变更问题,推荐方法1,符合Terraform对S3资源的模块化管理最佳实践。
内容的提问来源于stack exchange,提问作者Fir3Chi3f

