Validation Rules
เพิ่ม validation block ใน variable เพื่อ enforce rule กับค่า input — fail fast แทนรอ apply ผิดพลาด
ทำไมต้องใช้ Validation?
# ❌ ไม่มี validation
variable "environment" {
type = string
}
# user ใส่ "Prod" หรือ "PRODUCTION" หรือ "prdo" ก็ผ่าน type check
# → apply แล้วเจอ bug ตอน runtime
# ✅ มี validation
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of: dev, staging, prod."
}
}
→ Terraform reject ตั้งแต่ตอน plan
Validation Block Syntax
variable "<NAME>" {
type = <TYPE>
validation {
condition = <BOOL_EXPRESSION>
error_message = "..."
}
validation {
# มีหลาย validation block ได้
condition = ...
error_message = "..."
}
}
ตัวอย่าง Validations ที่ใช้บ่อย
1. Enum (whitelist values)
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of: dev, staging, prod."
}
}
2. Range (number)
variable "instance_count" {
type = number
validation {
condition = var.instance_count >= 1 && var.instance_count <= 10
error_message = "Instance count must be between 1 and 10."
}
}
3. Regex (string format)
variable "vpc_cidr" {
type = string
validation {
condition = can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$", var.vpc_cidr))
error_message = "VPC CIDR must be a valid CIDR notation (e.g., 10.0.0.0/16)."
}
}
4. Length
variable "name" {
type = string
validation {
condition = length(var.name) >= 3 && length(var.name) <= 32
error_message = "Name must be between 3 and 32 characters."
}
}
5. Multiple Conditions
variable "instance_type" {
type = string
validation {
condition = can(regex("^[a-z0-9]+\\.[a-z0-9]+$", var.instance_type))
error_message = "Instance type must follow format like 't3.micro'."
}
validation {
condition = !startswith(var.instance_type, "t1.")
error_message = "t1 instance types are deprecated."
}
}
Function can() — สำคัญมาก!
can() ห่อ expression — return true ถ้าไม่ throw error, false ถ้า throw
# ❌ ผิด — regex throw error ถ้า input ไม่ใช่ string
condition = regex("^[0-9]+$", var.x) != ""
# ✅ ถูก — can() catch error
condition = can(regex("^[0-9]+$", var.x))
ใช้บ่อยมากกับ regex, type conversion, list access
Cross-Variable Validation (Terraform 1.9+)
ก่อนหน้า 1.9 — validation อ้างได้แค่ var.<self>
ตั้งแต่ 1.9 — อ้าง variable อื่นได้แล้ว
variable "min_size" { type = number }
variable "max_size" { type = number }
variable "max_size" {
type = number
validation {
condition = var.max_size >= var.min_size
error_message = "max_size must be >= min_size."
}
}
ตัวอย่าง: Production Validation Set
variables.tf
variable "environment" {
type = string
description = "Environment name"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be: dev, staging, or prod."
}
}
variable "vpc_cidr" {
type = string
description = "VPC CIDR block"
validation {
condition = can(cidrsubnet(var.vpc_cidr, 0, 0))
error_message = "Must be a valid CIDR (e.g., 10.0.0.0/16)."
}
validation {
condition = tonumber(split("/", var.vpc_cidr)[1]) <= 24
error_message = "VPC CIDR mask must be /24 or larger (e.g., /16, /20)."
}
}
variable "instance_type" {
type = string
description = "EC2 instance type"
validation {
condition = can(regex("^t[23]\\.|^m5\\.|^c5\\.", var.instance_type))
error_message = "Only t2/t3/m5/c5 family instances allowed."
}
}
variable "tags" {
type = map(string)
description = "Tags to apply to all resources"
validation {
condition = contains(keys(var.tags), "Environment")
error_message = "tags must include 'Environment' key."
}
validation {
condition = contains(keys(var.tags), "Owner")
error_message = "tags must include 'Owner' key."
}
}
variable "subnet_count" {
type = number
description = "Number of subnets"
default = 2
validation {
condition = var.subnet_count >= 2 && var.subnet_count <= 6
error_message = "subnet_count must be 2-6 (matching AZ count)."
}
}
Custom Conditions ใน Output (Terraform 1.2+)
นอกจาก variable — output block ก็มี precondition กับ postcondition
output "instance_id" {
value = aws_instance.web.id
precondition {
condition = aws_instance.web.instance_type != "t1.micro"
error_message = "t1.micro is deprecated."
}
}
ดูใน Section 6: Outputs / Preconditions
Validation Errors ตอน Plan
$ terraform plan -var="environment=Prod"
╷
│ Error: Invalid value for variable
│
│ on variables.tf line 1:
│ 1: variable "environment" {
│
│ Environment must be: dev, staging, or prod.
│
│ This was checked by the validation rule at variables.tf:5,3-13.
╵
Anti-Patterns
# ❌ ไม่ validate รูปแบบที่ provider จะ validate ให้อยู่แล้ว
variable "instance_type" {
validation {
condition = startswith(var.instance_type, "t")
error_message = "Must start with t."
}
}
# AWS provider จะ error เองถ้า instance type ผิด
# ✅ Validate business rule ที่ provider ไม่รู้
variable "instance_type" {
validation {
condition = !contains(["t1.micro", "t2.nano"], var.instance_type)
error_message = "Use at least t3.small for our workloads."
}
}
สรุป
validationblock ในvariable— fail fast ตั้งแต่ plancondition= boolean expressionerror_message= ข้อความที่ user เห็น- ใช้
can()ห่อ regex / type conversion เพื่อกัน error - Terraform 1.9+ — validate ข้าม variable ได้
- Validate business rule ไม่ใช่ provider rule (ปล่อยให้ provider เช็คเอง)
ต่อไป → Local Values