Terraform Part4

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

  1. Prompt during terraform apply
    • Terraform asks for input when applying configuration.
    • Useful for testing but not efficient for automation.
  2. Command-line Arguments

Passes the variable directly in the command.

terraform apply -var=”subnet_cidr_block=10.0.10.0/24″

  1. 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. 🚀

  1. Create environment variable

Terraform follows a precedence order to determine which value to use.

Terraform Variable Precedence Order (Highest to Lowest)

  1. Command-line Argument (-var flag)

terraform apply -var=”subnet_cidr_block=10.0.20.0/24″

This takes the highest priority.

  1. Environment Variable (TF_VAR_<variable_name>)

export TF_VAR_subnet_cidr_block=”10.0.30.0/24″

Used if no -var flag is provided.

  1. 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.

  1. 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

  1. Using Environment Variables
    • Terraform automatically picks up credentials set as environment variables.
    • These variables are the same as required for the AWS CLI:
export AWS_ACCESS_KEY_ID=”your-access-key” export AWS_SECRET_ACCESS_KEY=”your-secret-key” export AWS_DEFAULT_REGION=”us-west-2″
    • This method ensures credentials remain outside configuration files.
  1. Using AWS Credentials File (~/.aws/credentials)
    • AWS CLI allows configuring credentials globally using:
aws configure This prompts for:
      • 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.
Setting Terraform-Specific Environment Variables
  • Terraform uses TF_VAR_ prefix for setting global environment variables.
  • Example:
export TF_VAR_availability_zone=”us-west-1a”
  • No spaces around = when defining environment variables.
Using environment variables or AWS credentials file improves security, avoids hardcoded credentials, and allows seamless authentication across tools like AWS CLI and Terraform.

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.