Terraform Variables: A Guide to Dynamic Infrastructure Configuration
Terraform, a powerful Infrastructure as Code (IaC) tool, simplifies cloud resource provisioning by allowing infrastructure to be defined in code. One of Terraform’s key features is variables, which enable dynamic and reusable configurations. In this blog post, we’ll explore Terraform variables, their types, usage, and best practices.
What Are Terraform Variables?
Terraform variables allow users to parameterize configurations, making them more flexible and easier to manage. Instead of hardcoding values in Terraform files, we can define variables and assign values dynamically.
Why Use Variables in Terraform?
- Reusability – Avoid duplication by using the same configuration for different environments.
- Flexibility – Easily modify infrastructure without changing the core code.
- Security – Keep sensitive information (e.g., access keys) out of code by defining them separately.
Types of Terraform Variables
Terraform supports different types of variables to handle various data inputs:
1. Input Variables
Input variables define parameters that can be passed into a Terraform configuration. They are declared using the variable block.
Example: Defining an Input Variable
variable “region” { description = “AWS region” type = string default = “us-east-1” } |
Here, we define a variable named region, assign it a default value, and provide a description.
Using the Variable in a Resource
provider “aws” { region = var.region } |
The var.region syntax references the variable within Terraform configurations.
2. Environment Variables
Terraform allows setting variables through environment variables for better security and automation.
Example: Setting an Environment Variable
export TF_VAR_region=”us-west-2″
This assigns the region variable without modifying the Terraform code. To use this environment variable, we must define same input variable in TF file.
3. Variable Files (.tfvars)
Variable values can be stored in separate .tfvars files, keeping configurations modular.
Example: Creating a terraform.tfvars File
region = “us-west-1”
instance_type = “t2.micro”
To apply these values, use:
terraform apply -var-file=”terraform.tfvars”
4. Output Variables
Output variables display useful information after Terraform execution.
Example: Defining an Output Variable
output “vpc_id” {
value = aws_vpc.main.id
}
After applying Terraform, this outputs the created VPC ID.
Best Practices for Terraform Variables
✔Use Default Values Where Possible – Define sensible defaults to minimize required inputs.
✔ Store Sensitive Data Securely – Use Terraform secrets management or environment variables instead of hardcoding sensitive values.
✔ Use Variable Validation – Ensure inputs meet required criteria.
Example: Adding Validation to a Variable
variable “instance_type” {
type = string
default = “t2.micro”
validation {
condition = contains([“t2.micro”, “t3.small”, “t3.medium”], var.instance_type)
error_message = “Allowed values: t2.micro, t3.small, t3.medium.”
}
}
Terraform Variables and Passing Values
Instead of hardcoding values like cidr_block, we can define variables for flexibility and reuse across multiple environments (e.g., development and production).
variable “subnet_cidr_block” { description = “subnet cidr block” } resource “aws_vpc” “development-vpc” { cidr_block = “10.0.0.0/16” tags = { Name = “development” } } resource “aws_subnet” “dev-subnet-1” { vpc_id = aws_vpc.development-vpc.id cidr_block = var.subnet_cidr_block availability_zone = “eu-central-1a” tags = { Name = “subnet-1-dev” } } |
Here, subnet_cidr_block is a variable, referenced in the subnet resource.
Ways to Assign Variable Values
- Prompt during terraform apply
- Terraform asks for input when applying configuration.
- Useful for testing but not efficient for automation.
- Command-line Arguments
Passes the variable directly in the command.
terraform apply -var=”subnet_cidr_block=10.0.10.0/24″
- Using a Variable File (terraform.tfvars)
Define key-value pairs inside terraform.tfvars:
subnet_cidr_block = “10.0.10.0/24”
Terraform automatically detects and loads this file.
terraform apply -var-file=”terraform.tfvars”
Using terraform.tfvars is the best practice for automation, as it eliminates manual input and keeps configurations organized. 🚀
- Create environment variable
Terraform follows a precedence order to determine which value to use.
Terraform Variable Precedence Order (Highest to Lowest)
- Command-line Argument (-var flag)
terraform apply -var=”subnet_cidr_block=10.0.20.0/24″
This takes the highest priority.
- Environment Variable (TF_VAR_<variable_name>)
export TF_VAR_subnet_cidr_block=”10.0.30.0/24″
Used if no -var flag is provided.
- Variable Definition Files (terraform.tfvars or .auto.tfvars)
Example (terraform.tfvars):
subnet_cidr_block = “10.0.40.0/24”
Used if neither command-line nor environment variable is set.
- Default Value in variables.tf (if defined in variable block)
variable “subnet_cidr_block” {
description = “subnet cidr block”
default = “10.0.50.0/24”
}
Used if no other value is provided.
✅ If you provide both -var in the command and an environment variable, Terraform will use the command-line argument (-var) as it has the highest precedence.
🚀 Best Practice: Use variable files (terraform.tfvars) for automation and avoid hardcoding values in the command.
Use Case for Input Variables
Useful for reusing Terraform configuration files across multiple environments (e.g., development, staging, production).
Instead of duplicating configuration files, use variables to change environment-specific parameters.
Example: Use a variables file like terraform_dev.tfvars and apply it using:
terraform apply -var-file=”terraform_dev.tfvars”
Type Constraints in Terraform Variables
Defining Types: Variables can have specific types such as:
variable “subnet_cidr_block” {
type = string
}
If a value of a different type is passed (e.g., list instead of string), Terraform throws an error.
Common Variable Types
Type | Example |
string | “10.0.0.0/16” |
number | 22 |
bool | true |
list | [“10.0.0.0/16”, “10.0.1.0/24”] |
map | { env = “dev”, region = “us-east-1” } |
Using Lists in Terraform
Example: List of CIDR blocks
variable “cidr_blocks” {
type = list(string)
}
variable “cidr_blocks” { description = “cidr blocks for vpc and subnets” type = list(string) } resource “aws_vpc” “development-vpc” { cidr_block = var.cidr_blocks[0] tags = { Name = “development” } } resource “aws_subnet” “dev-subnet-1” { vpc_id = aws_vpc.development-vpc.id cidr_block = var.cidr_blocks[1] availability_zone = “eu-central-1a” tags = { Name = “subnet-1-dev” } } Terraform Variable File (terraform-dev.tfvars) cidr_blocks = [“10.0.0.0/16”, “10.0.10.0/24”]
|
Accessing list values:
cidr_block = var.cidr_blocks[0]
Using Objects in Terraform
Example: List of objects with attributes
variable “subnet_configs” {
type = list(object({
name = string
cidr_block = string
}))
}
Accessing Object Attributes in main.tf
resource “aws_subnet” “example” {
vpc_id = aws_vpc.main.id
cidr_block = var.subnet_configs[0].cidr_block
tags = {
Name = var.subnet_configs[0].name
}
}
variable “cidr_blocks” { description = “CIDR blocks for VPC and subnets” type = list(object({ cidr_block = string name = string })) } resource “aws_vpc” “development-vpc” { cidr_block = var.cidr_blocks[0].cidr_block tags = { Name = var.cidr_blocks[0].name } } resource “aws_subnet” “dev-subnet-1” { vpc_id = aws_vpc.development-vpc.id cidr_block = var.cidr_blocks[1].cidr_block availability_zone = “eu-central-1a” tags = { Name = var.cidr_blocks[1].name } } Assigning Values in terraform.tfvars cidr_blocks = [ { cidr_block = “10.0.0.0/16”, name = “dev-vpc” }, { cidr_block = “10.0.10.0/24”, name = “dev-subnet” } ] |
Setting AWS Credentials Securely
Avoid Hardcoding Credentials
Storing AWS credentials directly in Terraform configuration files is a security risk, especially when committing to version control (e.g., Git).Two Secure Ways to Set AWS Credentials
- Using Environment Variables
- Terraform automatically picks up credentials set as environment variables.
- These variables are the same as required for the AWS CLI:
-
- This method ensures credentials remain outside configuration files.
- Using AWS Credentials File (~/.aws/credentials)
- AWS CLI allows configuring credentials globally using:
-
-
- Access Key ID
- Secret Key ID
- Default Region
- Credentials are stored in ~/.aws/credentials and automatically used by Terraform.
-
Verifying Credentials with Terraform
- If environment variables or AWS credentials file are set, Terraform should authenticate without requiring credentials in .tf files.
- Each provider’s documentation lists supported authentication methods.
- Terraform uses TF_VAR_ prefix for setting global environment variables.
- Example:
- No spaces around = when defining environment variables.
Create .gitignore to Exclude Unnecessary Files
Exclude files that should not be committed:
.terraform/ # Locally installed providers (downloaded on `terraform init`) terraform.tfstate # Generated state file, updates with `terraform apply` terraform.tfvars # May contain sensitive data (e.g., passwords, keys) |
Include the Terraform lock file (.terraform.lock.hcl), as it stores provider versions and ensures consistency across environments.
Benefits of Using Input Variables
✔ Reusability: Use the same Terraform files for different environments.
✔ Consistency: Enforce type constraints to prevent incorrect values.
✔ Flexibility: Supports different data structures (strings, lists, objects).
✔ Collaboration: Helps teams pass values without modifying core configurations.
🚀 Best Practice: Store environment-specific values in .tfvars files to avoid manual input
Conclusion
Terraform variables enhance modularity, security, and flexibility, making infrastructure code easier to manage and scale. By effectively using input variables, environment variables, and variable files, DevOps teams can create robust, and reusable Terraform configurations.