Terraform Input Variables
Terraform has become a staple for Infrastructure as Code (IaC), allowing teams to define and manage infrastructure with declarative configuration files. A core component of this flexibility and power lies in input variables. They are the mechanism through which you can parameterize your configurations, making them reusable, adaptable, and easier to manage across different environments and teams.
This post will dive into what Terraform input variables are, how to declare and use them, explore their various types, and discuss best practices for managing them effectively.
Table of Contents
- What Are Terraform Input Variables?
- Declaring Input Variables
- Understanding Data Types
- Assigning Values to Variables
- Advanced Variable Features
- Why Effective Variable Management is Crucial
- Summary Table: Key Variable Concepts
- Conclusion
What Are Terraform Input Variables?
At their core, Terraform input variables are like function arguments in a programming language. They allow you to pass values into your Terraform modules or root configurations, customizing their behavior without modifying the underlying code.
Key Benefits:
- Reusability: Write a generic module once (e.g., for a web server) and reuse it for different applications or environments by simply changing the input variable values (like instance size or image ID).
- Modularity: Build complex infrastructure by combining smaller, self-contained modules that communicate and are configured via input variables.
- Maintainability: Centralize configuration changes. Instead of hunting through code, you update variable files or settings, reducing the risk of errors.
- Consistency: Enforce standards by parameterizing common settings, ensuring deployments follow established patterns.
Input variables decouple the data (your specific settings) from the logic (how resources are defined). This separation is fundamental to scalable and maintainable IaC.
Declaring Input Variables
Input variables are declared using variable
blocks, typically in a dedicated variables.tf
file for better organization.
Basic Syntax
variable "variable_name" {
# Arguments defining the variable's properties
}
The "variable_name"
is how you'll refer to this variable within your Terraform code (using var.variable_name
) and when assigning values to it.
Key Arguments
While several arguments can be used within a variable
block, three are essential for well-defined variables:
default
(Optional): Provides a default value for the variable. If a default is set, the variable becomes optional; Terraform will use this value if no other is provided.
variable "enable_monitoring" {
description = "Flag to enable detailed monitoring."
type = bool
default = true
}
The default
value must be a literal and cannot reference other objects.
type
(Optional but Highly Recommended): Specifies the data type of the variable (e.g., string
, number
, bool
, list(string)
, object(...)
). If omitted, the type is any
. Explicitly defining types enables Terraform to validate inputs early.
variable "instance_count" {
description = "Number of instances to create."
type = number
default = 1
}
description
(Optional but Highly Recommended): A string that explains the purpose of the variable. This is crucial for documentation and helps others (and your future self) understand how to use the module.
variable "image_id" {
description = "The ID of the machine image (AMI) to use for the server."
type = string
default = "ami-default123"
}
Understanding Data Types
Terraform supports a range of data types for input variables:
Primitive Types
string
: A sequence of Unicode characters (e.g.,"my-instance-name"
).number
: Numeric values, including integers and floating-point numbers (e.g.,3
,10.5
).bool
: Boolean values, eithertrue
orfalse
.
Collection Types
set(<TYPE>)
: An unordered collection of unique elements of the same specified type.
map(<TYPE>)
: A collection of key-value pairs, where keys are strings and all values are of the same specified type.
variable "common_tags" {
description = "A map of tags to apply to resources."
type = map(string)
default = {
Environment = "dev"
Project = "alpha"
}
}
list(<TYPE>)
: An ordered sequence of elements, all of the same specified type.
variable "subnet_ids" {
description = "A list of subnet IDs."
type = list(string)
default = ["subnet-abcde012", "subnet-fghij345"]
}
Structural Types
These allow for more complex, custom data structures:
tuple()
: An ordered sequence where elements can have different specified types.
object({<ATTR_NAME> = <TYPE>, ...})
: Defines a structure with named attributes, each potentially having a different type. This is very useful for grouping related configuration settings.
variable "server_configuration" {
description = "Configuration for a server instance."
type = object({
instance_type = string
ami_id = string
enable_ebs_opt = bool
tags = map(string)
})
default = {
instance_type = "t2.micro"
ami_id = "ami-0c55b31ad549f9278"
enable_ebs_opt = false
tags = {
Name = "DefaultServer"
}
}
}
The any
type can also be used if a variable needs to accept any type, but this bypasses type checking and should be used judiciously.
Assigning Values to Variables
Terraform offers several ways to set values for input variables declared in your root module:
Variable Definition Files (.tfvars
)
These are the most common way to manage persistent variable values, especially for different environments.
*.auto.tfvars
: Any files with the.auto.tfvars
(or.auto.tfvars.json
) extension are also automatically loaded in lexical order. This allows for splitting variable definitions across multiple files.- Custom
.tfvars
files: You can specify custom variable files using the-var-file
command-line flag.
terraform.tfvars
: If a file named terraform.tfvars
(or terraform.tfvars.json
) exists in the root directory, Terraform automatically loads it. Example terraform.tfvars
:
instance_name_prefix = "web"
instance_count = 3
common_tags = {
Environment = "production"
Team = "Frontend"
}
Command-Line Flags
-var-file="<path_to_file>"
: Loads variables from a specified file.
terraform apply -var-file="production.tfvars"
-var="<variable_name>=<value>"
: Sets an individual variable.
terraform apply -var="instance_count=5" -var='common_tags={Environment="staging"}'
Environment Variables
Terraform reads environment variables prefixed with TF_VAR_
.
export TF_VAR_instance_count=2
export TF_VAR_aws_region="us-east-1"
terraform apply
Order of Precedence
Terraform loads variables in the following order (later sources override earlier ones):
default
values invariable
blocks.- Environment variables (
TF_VAR_...
). terraform.tfvars
file.terraform.tfvars.json
file.*.auto.tfvars
and*.auto.tfvars.json
files (lexical order).-var-file
options on the command line (order of specification).-var
options on the command line (order of specification).
HCP Terraform workspace variables also have high precedence, typically acting like command-line options.
Advanced Variable Features
Terraform offers more advanced capabilities for variables:
Custom Validation Rules
You can define validation
blocks within a variable to enforce custom rules beyond basic type checking.
variable "image_id" {
type = string
description = "The ID of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI ID, starting with \"ami-\"."
}
}
This helps catch errors early and ensures inputs meet specific requirements.
Sensitive Variables
For confidential data like passwords or API keys, you can mark a variable as sensitive = true
.
variable "db_password" {
description = "Database administrator password."
type = string
sensitive = true
# It's good practice not to provide a default for sensitive variables.
}
Terraform will redact the values of sensitive variables from CLI output. However, these values are still stored in plain text in the Terraform state file, so state file security is paramount. For data that should not be in the state at all, ephemeral = true
can be used.
Why Effective Variable Management is Crucial
As infrastructure complexity grows and more teams adopt IaC, managing variables effectively becomes critical. While Terraform provides the foundational tools, ensuring consistency, security, and ease of use across an organization requires a more structured approach.
- Clarity and Consistency: Well-defined variables with clear descriptions and types make modules easier to understand and use, reducing misconfigurations.
- Environment Management: Separating variables for development, staging, and production is essential. This is often handled with different
.tfvars
files. - Secrets Management: Handling sensitive data requires care. While
sensitive = true
helps, integrating with dedicated secrets management tools or using platforms that offer secure variable storage is a best practice. - Governance and Collaboration: In larger organizations, ensuring that teams use variables correctly, adhere to naming conventions, and manage environment-specific configurations can be challenging.
This is where platforms built on top of or around Terraform, like Scalr, can provide significant value. Scalr offers features such as hierarchical variable management, environment-specific variable sets, built-in secrets management, and policy enforcement (Open Policy Agent integration). This allows organizations to centralize variable definitions, enforce standards, and provide a more streamlined and secure operational experience for Terraform users, especially when managing multiple workspaces, teams, and complex cloud environments. By abstracting some of the manual overhead, such platforms help teams focus on defining infrastructure rather than wrestling with the intricacies of variable organization at scale.
Summary Table: Key Variable Concepts
Feature/Argument | Purpose | Example Usage in |
---|---|---|
| Declares an input variable. |
|
| Documents the variable's purpose. |
|
| Specifies the expected data type for the variable's value. |
|
| Provides a default value, making the variable optional. |
|
| Marks the variable's value as sensitive, redacting it from CLI output. |
|
| Defines custom rules to validate the variable's value. |
|
| References the variable's value in configuration. |
|
Conclusion
Terraform input variables are fundamental to creating flexible, reusable, and maintainable infrastructure as code. By understanding how to declare them, leveraging the type system, and following best practices for assigning and managing their values, you can significantly improve your IaC workflows. For organizations looking to scale their Terraform operations, considering how to manage variables across teams and environments becomes paramount, and leveraging platforms designed for this purpose can offer substantial benefits in terms of efficiency, governance, and security.