Trong toàn bộ hệ sinh thái Terraform, không có thành phần nào quan trọng nhưng cũng dễ bị hiểu lầm và gây ra thảm họa vận hành nhiều như Terraform State (terraform.tfstate). Nhiều kỹ sư DevOps mới thường ngộ nhận rằng Terraform là một công cụ "stateless" kết nối trực tiếp mã HCL với Cloud API, hoặc coi file state chỉ là một bộ nhớ cache tạm thời có thể xóa đi tạo lại tùy ý.
Thực tế hoàn toàn trái ngược: State là nguồn chân lý duy nhất (Single Source of Truth) mà Terraform Core dựa vào để ánh xạ giữa các định danh trừu tượng trong mã nguồn (resource "aws_instance" "web") và các tài nguyên vật lý thực tế trên đám mây (i-0abcdef1234567890). Mất file state đồng nghĩa với việc bạn mất toàn bộ quyền kiểm soát hạ tầng qua IaC.
Trong bài viết chuyên sâu này, chúng ta sẽ "phẫu thuật" cấu trúc JSON Schema v4 của file state, bóc tách cơ chế phát hiện lệch cấu hình (Drift Detection) trong pha Refresh, và hướng dẫn quy trình đối soát hạ tầng an toàn bằng lệnh -refresh-only.
1. Phẫu Thuật Cấu Trúc JSON Schema v4 của File State
File terraform.tfstate thực chất là một tài liệu JSON có cấu trúc nghiêm ngặt (hiện tại là Schema format version 4). Hiểu rõ từng trường siêu dữ liệu (metadata) trong file này là chìa khóa để xử lý sự cố khi state bị corrupt.
1.1. Bốn Trường Siêu Dữ Liệu Cốt Lõi (Core Metadata)
{
"version": 4,
"terraform_version": "1.7.5",
"serial": 42,
"lineage": "e9b28b7a-5c1a-428a-9c7a-1123456789ab",
"outputs": {},
"resources": [ ... ]
}
version(Integer): Phiên bản cấu trúc schema của file state (hiện tại luôn là4).terraform_version(String): Phiên bản Terraform CLI nhị phân đã tạo ra hoặc chỉnh sửa file state này lần cuối.serial(Integer): Số nguyên đơn điệu tăng dần (+1) sau mỗi lầnterraform applythành công. Đây là con số quan trọng bậc nhất giúp các Backend (như S3/Consul/HCP Terraform) phát hiện tình trạng ghi đè state cũ hơn (Out-of-order write / Stale State).lineage(UUID String): Mã định danh duy nhất của "dòng họ" state, được sinh ra ngẫu nhiên khi khởi tạo state lần đầu. Nếu bạn cố tình ghi đè một state cólineagekhác vào backend hiện tại, Terraform sẽ lập tức từ chối vì coi đây là hai dự án hoàn toàn xa lạ.
1.2. Cấu Trúc Khối resources
Mỗi tài nguyên quản trị được lưu trữ với đầy đủ định danh và phụ thuộc:
{
"mode": "managed",
"type": "aws_subnet",
"name": "public_subnet",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"arn": "arn:aws:ec2:ap-southeast-1:123456789012:subnet/subnet-0123456789abcdef0",
"cidr_block": "10.0.1.0/24",
"id": "subnet-0123456789abcdef0",
"vpc_id": "vpc-0987654321fedcba0"
},
"sensitive_attributes": [],
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6MTIwMDAwMDAwMDAwMH19",
"dependencies": [
"aws_vpc.main_vpc"
]
}
]
}
Thuộc tính private là một chuỗi mã hóa Base64 chứa dữ liệu nội bộ của riêng Provider (thời gian timeout, internal state context). Kỹ sư tuyệt đối không được tự ý sửa tay trường này.
2. Cơ Chế Drift Detection Trong Pha Refresh: State vs Thực Tế
Một trong những luận đề trung tâm của quản trị IaC hiện đại: "State không phải là thực tế" (State is not Reality). File state chỉ là bức ảnh chụp (Snapshot) tại thời điểm gần nhất lệnh apply chạy thành công.
Nếu một quản trị viên đăng nhập vào AWS Management Console và bấm nút xóa Security Group Rule hoặc đổi Instance Type EC2 ngoài luồng (Out-of-band change), State file hoàn toàn không tự động biết được điều đó cho đến khi pha Refresh được kích hoạt.
2.1. Ma Trận Ba Góc Nhìn (The 3-Way Reconciliation Matrix)
Khi tính toán Execution Plan, Terraform xử lý thuật toán đối soát 3 chiều giữa Mã HCL (Desired), State File (Prior State) và Hạ Tầng Cloud (Actual Reality):
| Tình Huống Thực Tế | Trạng Thái HCL | Trạng Thái State | Trạng Thái Cloud Thật | Hành Động Của Terraform Plan |
|---|---|---|---|---|
| Bình thường (In-Sync) | Có khai báo | Có lưu | Tồn tại đúng cấu hình | No changes |
| Xóa ngoài luồng (Out-of-band Delete) | Có khai báo | Có lưu | Đã bị xóa trên Console | Ghi nhận Drift $\rightarrow$ Kế hoạch: + Create lại |
| Sửa ngoài luồng (Out-of-band Modify) | Có khai báo | Có lưu | Bị đổi thuộc tính | Ghi nhận Drift $\rightarrow$ Kế hoạch: ~ Update về HCL |
| Tài nguyên mới trong HCL | Có khai báo | Chưa có | Chưa có | Kế hoạch: + Create mới |
| Xóa bỏ trong HCL | Đã xóa | Có lưu | Tồn tại trên Cloud | Kế hoạch: - Destroy trên Cloud |
3. Kỹ Thuật Đối Soát An Toàn Với plan/apply -refresh-only
Từ phiên bản Terraform 0.15.4 và chính thức hoàn thiện ở Terraform 1.x, HashiCorp đã giới thiệu cờ -refresh-only thay thế cho lệnh terraform refresh cũ (vốn đã bị deprecated vì nguy cơ tự động ghi đè mù quáng).
3.1. Tại Sao Không Dùng terraform refresh Cũ?
Lệnh terraform refresh cũ sẽ lập tức đọc Cloud API và ghi đè thẳng vào file State mà không cho kỹ sư xem trước (preview). Nếu Cloud API bị timeout trả về mã lỗi giả 404, terraform refresh có thể xóa sạch toàn bộ resource trong state, khiến lần apply tiếp theo đòi tạo mới hàng loạt.
3.2. Quy Trình Chuẩn Với -refresh-only
# Bước 1: Xem trước sự sai lệch mà KHÔNG thay đổi hạ tầng hay ghi đè state
terraform plan -refresh-only
# Output hiển thị rõ ràng từng thuộc tính bị drift ngoài luồng:
# ~ resource "aws_security_group" "web_sg" {
# ~ tags = {
# - "ModifiedBy" = "ConsoleUser" -> null
# }
# }
# Would you like to update the state to reflect these detected changes?
# Bước 2: Xác nhận cập nhật State file cho khớp với thực tế Cloud
terraform apply -refresh-only
Lệnh terraform apply -refresh-only hoàn toàn không tác động hay phá hủy tài nguyên thực tế. Lệnh này chỉ đồng bộ hóa trí nhớ của State file cho khớp với thực tế đám mây hiện hữu.
4. Lỗ Hổng Bảo Mật Chết Người: Plaintext Secrets Trong State
Một trong những sự thật đáng sợ nhất đối với các kỹ sư bảo mật: Terraform State lưu trữ 100% thuộc tính ở dạng Plaintext thô.
Ngay cả khi bạn sử dụng biến khai báo sensitive = true, hoặc lấy mật khẩu từ AWS Secrets Manager / HashiCorp Vault:
variable "db_password" {
type = string
sensitive = true
}
resource "aws_db_instance" "production_rds" {
allocated_storage = 50
engine = "postgres"
username = "postgres_admin"
password = var.db_password # Được gán nhãn sensitive
}
Khi chạy terraform apply, Terraform CLI sẽ che mờ (sensitive value) trên màn hình terminal. Nhưng khi mở file terraform.tfstate ra:
"attributes": {
"username": "postgres_admin",
"password": "MySuperSecretMasterPassword2026!"
}
Quy tắc An ninh Bất Biến: Tuyệt đối không bao giờ commit file terraform.tfstate hoặc *.tfstate.backup vào Git repository công ty. Bất kỳ ai có quyền clone repository đều có thể trích xuất toàn bộ mật khẩu cơ sở dữ liệu, API Key, và TLS Private Key của doanh nghiệp.
5. Tổng Kết & Checklist Quản Trị State Chuẩn Senior
Checklist 5 Điều Phải Nhớ Cho Kỹ Sư IaC:
- Không bao giờ sửa tay JSON state: Mọi thao tác đổi tên hoặc xóa tài nguyên khỏi state phải dùng CLI chuẩn (
terraform state mv,terraform state rm). - Luôn kiểm tra
.gitignore: Đảm bảo*.tfstate,*.tfstate.*,.terraform/luôn nằm trong danh sách loại trừ trước commit đầu tiên. - Sử dụng
-refresh-onlyđể bắt Drift: Định kỳ chạyterraform plan -refresh-onlytrên CI/CD để phát hiện các thay đổi "chui" ngoài console. - Theo dõi
serialvàlineage: Đảm bảo không xảy ra xung đột ghi đè state cũ khi nhiều kỹ sư làm việc song song. - Chuẩn bị chuyển dịch lên Remote State: Trong bài tiếp theo, chúng ta sẽ xây dựng hệ thống Remote State với AWS S3 và DynamoDB State Locking để giải quyết triệt để bài toán làm việc nhóm và bảo mật cấp Enterprise.
Bài viết thuộc Series đào tạo Terraform Thực Chiến độc quyền trên ShowTech.vn.