Improve Terraform Configurations with Variable Validation

Let’s look at Terraform variable validation. I find it certainly useful when writing Terraform. This applies whether that be within a module or a direct resource update. Implementing the likes of variable validation helps you catch any potential errors early. This is certainly a great asset in preventing misconfigurations within your Terraform resources.

Understanding Terraform Variable Validation

Variable validation within Terraform has been around for a while, since 0.13. It allows you to define specific criteria that the variable input must match. Within this blog post, I will be showing some examples of this.

Firstly, lets look at the basic structure of variable validation, the block consists of two key components:

  1. The condition that the variable value must meet
  2. An error message that will appear if the conditional value is not met
variable "test" {
  type        = string
  description = "Test variable"
  validation {
    condition     = 
    error_message = "Error message if condition is not true."
  }
}

Some Azure practical examples

My examples will be Azure focused, but variable validation can be used within any sort of Terraform configuration

Restricting Azure VM Sizes

You have a variable called azure_vm_size, that must use a VM size of Standard_D4ds_v5 or Standard_DS2_v4. Lets create the variable validation:

variable "azure_vm_size" {
  type        = string
  description = "Size of the Azure VM"
  validation {
    condition     = contains(["Standard_DS2_v4", "Standard_D4ds_v5"], var.vm_size)
    error_message = "VM size can only be one of Standard_D4ds_v5, Standard_DS2_v4."
  }
}

Notice above, variable validation now in place for azure_vm_size

Enforcing VM Naming Conventions

Lets look at variable validation to ensure the VM name must start with vm-tamops-*

variable "vm_name" {
  type        = string
  description = "Name of the Azure resource group"
  validation {
    condition     = can(regex("^vm-tamops", var.vm_name))
    error_message = "VM Name name must start with 'vm-tamops'."
  }
}

Similar as before, with the condition now using regex to capture the variable vm_name

Example Validating Resource Group Deployments

main.tf

resource "azurerm_resource_group" "tamopsrg" {
  name     = "${var.rg_name}-${var.environment}"
  location = "West Europe"
}

variables.tf

variable "environment" {
  description = "The environment for the resources"
  type        = string
  validation {
    condition     = contains(["dev", "test", "prod"], var.environment)
    error_message = "Environment must be one of 'dev', 'test', or 'prod'."
  }
}

variable "rg_name" {
  type        = string
  description = "Name of the Azure resource group"
  validation {
    condition     = can(regex("^rg-tamops", var.rg_name))
    error_message = "Resource group name must start with 'rg-tamops'."
  }
}

examples.tfvars

environment = "preview"
rg_name     = "tamops-rg"

Now when I run: terraform plan -var-file="example.tfvars" with incorrect variable values, see below. It gives clear error messaging as to why the current plan is failing. Awesome!

terraform plan -var-file="example.tfvars"

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: Invalid value for variable
│ 
│   on example.tfvars line 1:
│    1: environment = "preview"
│     ├────────────────
│     │ var.environment is "preview"
│ 
│ Environment must be one of 'dev', 'test', or 'prod'.
│ 
│ This was checked by the validation rule at variables.tf:4,3-13.
╵
╷
│ Error: Invalid value for variable
│ 
│   on example.tfvars line 2:
│    2: rg_name     = "tamops-rg"
│     ├────────────────
│     │ var.rg_name is "tamops-rg"
│ 
│ Resource group name must start with 'rg-tamops'.
│ 
│ This was checked by the validation rule at variables.tf:13,3-13.

Slightly more Complex Validation

With the beauty of variable validation, you can have it as simple or some-what complex as you want. Seeing below – an example

variable "ip_address" {
  type        = string
  description = "Allowed IP that can be used"
  validation {
    condition     = can(regex("^10\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$", var.ip_address))
    error_message = "The IP address must be within the range 10.0.0.0 to 10.255.255.255."
  }
}

Example error output when IP address is not in the required range:

╷
│ Error: Invalid value for variable
│ 
│   on example.tfvars line 3:
│    3: ip_address  = "192.168.0.1"
│     ├────────────────
│     │ var.ip_address is "192.168.0.1"
│ 
│ The IP address must be within the range 10.0.0.0 to 10.255.255.255.
│ 
│ This was checked by the validation rule at variables.tf:22,3-13.

A few recommended best practices when using Terraform Variable Validation

  1. Use accurate and descriptive error messages: Just like any error messaging, provide clear and actionable error messages that will guide others to what the correct value(s) should be
  2. Make use of Terraform functions: Lots of functions available, with the likes of can(), contains() and length() are certainly useful for your variable validation
  3. Possible to use multiple conditions: When your validations are getting more complex, you can use logical operators – such as || and &&
  4. Keep it Simple: Start simple and increase complexity only when needed

Terraform variable validation can be very useful. It is a powerful tool within your automation. Spend some time introducing it. You will certainly see the reward of improving reliability. It also enhances the maintainability of your Terraform configurations. By implementing thorough validations, you can catch configuration errors early. You can enforce best practices. This approach provides clear guidance to users of your Terraform configurations and modules.

GitHub repository containing example code above

Leave a Reply

Discover more from Thomas Thornton Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading

Discover more from Thomas Thornton Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading