State Versioning
เก็บ history ของ state file — เพื่อ recovery ถ้าเสีย, audit ใครเปลี่ยนอะไร
ทำไมต้อง Version?
State file = source of truth ของ infrastructure
- ถ้าเสีย = พังหมด
- ถ้าเปลี่ยนผิด = recover ยาก
→ Versioning = backup automatic
S3 Versioning
ตั้งค่าใน bootstrap:
resource "aws_s3_bucket" "tfstate" {
bucket = "my-tfstate"
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration {
status = "Enabled" # ⭐
}
}
ทุกครั้งที่ Terraform write state → S3 เก็บ version ใหม่ + เก็บเก่าไว้
List Versions
aws s3api list-object-versions \
--bucket my-tfstate \
--prefix prod/terraform.tfstate
{
"Versions": [
{
"Key": "prod/terraform.tfstate",
"VersionId": "abc123",
"LastModified": "2026-05-07T10:30:00Z",
"IsLatest": true
},
{
"Key": "prod/terraform.tfstate",
"VersionId": "def456",
"LastModified": "2026-05-07T09:15:00Z",
"IsLatest": false
}
]
}
Restore Version
# Download version เก่า
aws s3api get-object \
--bucket my-tfstate \
--key prod/terraform.tfstate \
--version-id def456 \
state-old.json
# Push กลับ (ระวัง!)
terraform state push state-old.json
Restore state เก่า = drift กับ reality ทำเฉพาะตอน:
- State เพิ่ง corrupt (เพิ่งกี่นาที)
- รู้แน่ว่า cloud reality ยังไม่เปลี่ยน
Lifecycle Policy
ป้องกัน S3 cost จาก version เยอะ:
resource "aws_s3_bucket_lifecycle_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule {
id = "expire-old-versions"
status = "Enabled"
filter {}
noncurrent_version_expiration {
noncurrent_days = 90 # ลบ version เก่ากว่า 90 วัน
}
noncurrent_version_transition {
noncurrent_days = 30
storage_class = "STANDARD_IA" # ย้ายไป IA หลัง 30 วัน
}
}
}
Backup ทุก Apply
Terraform local มี .tfstate.backup:
project/
├── terraform.tfstate # current
└── terraform.tfstate.backup # before last apply
ถ้าอยากกู้ครั้งล่าสุด:
mv terraform.tfstate terraform.tfstate.bad
mv terraform.tfstate.backup terraform.tfstate
(แค่ครั้งล่าสุด — ใช้ remote versioning ดีกว่า)
Terraform Cloud Versioning
Terraform Cloud / Enterprise — มี state versioning ในตัว + UI
- ดู state ทุก version ผ่าน web UI
- Compare diff ระหว่าง version
- Restore in 1 click
Audit Trail
ใช้ S3 versioning + CloudTrail:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=my-tfstate
→ เห็น:
- ใคร PUT state file
- ตอนไหน
- จาก IP ไหน
State Snapshot ก่อน Risky Operation
ก่อนทำการ risky (เช่น state mv, state rm):
# Manual backup
terraform state pull > backup-$(date +%Y%m%d-%H%M%S).tfstate
# ถ้าเกิดอะไรผิด → restore
terraform state push backup-20260507-143000.tfstate
Version State + Lock Together
# S3 with versioning
resource "aws_s3_bucket" "tfstate" {
bucket = "my-tfstate"
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_lifecycle_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule {
id = "manage-old-versions"
status = "Enabled"
filter {}
noncurrent_version_expiration {
noncurrent_days = 90
}
}
}
# DynamoDB for lock + PITR
resource "aws_dynamodb_table" "tfstate_lock" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
point_in_time_recovery {
enabled = true # ⭐
}
}
DynamoDB Lock Table PITR
Point-in-Time Recovery:
point_in_time_recovery {
enabled = true
}
→ Lock table backup automatic 35 วัน
Cross-Region Replication
สำหรับ DR:
resource "aws_s3_bucket_replication_configuration" "tfstate" {
role = aws_iam_role.replication.arn
bucket = aws_s3_bucket.tfstate.id
rule {
id = "replicate-to-dr"
status = "Enabled"
destination {
bucket = aws_s3_bucket.tfstate_dr.arn # bucket ใน region อื่น
storage_class = "STANDARD_IA"
}
}
}
→ DR region มี copy ของ state ตลอดเวลา
Best Practices
✅ DO:
- Enable S3 versioning ตั้งแต่ bootstrap
- Lifecycle policy เพื่อ cost control
- Manual backup ก่อน state mv/rm
- DynamoDB PITR + bucket replication ใน prod
- CloudTrail logging
❌ DON'T:
- ห้าม disable versioning
- ห้าม delete S3 bucket ที่มี state (ใช้ MFA delete protection)
- ห้าม push state เก่าโดยไม่ verify reality
MFA Delete (Extra Protection)
aws s3api put-bucket-versioning \
--bucket my-tfstate \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::123456789012:mfa/user 123456"
→ ลบ version ต้องใช้ MFA — ป้องกัน accidental deletion
สรุป
- Versioning = backup automatic ทุกครั้งที่ write state
- S3 ใช้ versioning + lifecycle policy
- DynamoDB ใช้ PITR สำหรับ lock table
- Restore ผ่าน
aws s3api get-object+terraform state push - Cross-region replication สำหรับ DR
- MFA Delete ป้องกัน accidental deletion
ต่อไป → Sensitive Data in State