Terraform Variables
Last updated
Was this helpful?
Last updated
Was this helpful?
Input variables make your Terraform configuration more flexible by defining values that your end users can assign to customize the configuration. They provide a consistent interface to change how a given configuration behaves.
Unlike variables found in programming languages, Terraform's input variables don't change values during a Terraform run such as plan, apply, or destroy. Instead, they allow users to more safely customize their infrastructure by assigning different values to the variables before execution begins, rather than editing configuration files manually.
In this tutorial, you will use Terraform to deploy a web application on AWS. The supporting infrastructure includes a VPC, load balancer, and EC2 instances. You will parameterize this configuration with Terraform input variables. Finally, you will interpolate variables into strings, use variables with functions, and use variable validation.
Clone the Learn Terraform variables GitHub repository for this tutorial.
Change to the repository directory.
The configuration in main.tf
defines a web application, including a VPC, load balancer, and EC2 instances.
Variable declarations can appear anywhere in your configuration files. However, we recommend putting them into a separate file called variables.tf
to make it easier for users to understand how they can customize the configuration.
To parameterize an argument with an input variable, you must first define the variable, then replace the hardcoded value with a reference to that variable in your configuration.
Add a block declaring a variable named aws_region
to variables.tf
.
variables.tfCopy
Variable blocks have three optional arguments.
Description: A short description to document the purpose of the variable.
Type: The type of data contained in the variable.
Default: The default value.
We recommend setting a description and type for all variables, and setting a default value when practical.
If you do not set a default value for a variable, you must assign a value before Terraform can apply the configuration. Terraform does not support unassigned variables. You will review some of the ways to assign values to variables later in this tutorial.
Variable values must be literal values, and cannot use computed values like resource attributes, expressions, or other variables. You can refer to variables in your configuration with var.<variable_name>
.
Edit the provider block in main.tf
to use the new aws_region
variable.
Add another declaration for the vpc_cidr_block
variable to variables.tf
.
Now, replace the hard-coded value for the VPC's CIDR block with a variable in main.tf
.
main.tf
Apply the updated configuration. Since the default values of these variables are the same as the hard-coded values they replaced, there will be no changes.
Terraform supports several variable types in addition to string
.
Use a number
type to define the number of instances supported by this configuration. Add the following to variables.tf
.
Update EC2 instances to use the instance_count
variable in main.tf
.
When Terraform interprets values, either hard-coded or from variables, it will convert them into the correct type if possible. So the instance_count
variable would also work using a string ("2"
) instead of a number (2
). We recommend using the most appropriate type in variable definitions to helps users of your configuration know the appropriate data type to use, as well as to catch configuration errors early.
In addition to strings and numbers, Terraform supports several other variable types. A variable with type bool
represents true/false values.
Use a bool
type variable to control whether to configure a VPN gateway for your VPC. Add the following to variables.tf
.
Use a bool
type variable to control whether to configure a VPN gateway for your VPC. Add the following to variables.tf
.
Use this new variable in your VPC configuration by editing main.tf
as follows.
Leave the value for enable_nat_gateway
hard-coded. In any configuration, there may be some values that you want to let users configure with variables and others you wish to hard-code.
When developing Terraform modules, you will often use variables to make the module's attributes configurable, to make the module more flexible.
In contrast, when writing Terraform configuration for a specific project, you may choose to hard-code attributes if you do not want to let users configure them.
The variables you have used so far have all been single values. Terraform calls these types of variables simple. Terraform also supports collection variable types that contain more than one value. Terraform supports several collection variable types.
List: A sequence of values of the same type.
Map: A lookup table, matching keys to values, all of the same type.
Set: An unordered collection of unique values, all of the same type.
In this tutorial, you will use lists and a map, which are the most commonly used of these types. Sets are useful when you need a unique collection of values is needed, and the order of the items in the collection does not matter.
A likely place to use list variables is when setting the private_subnets
and public_subnets
arguments for the VPC. Make this configuration easier to use and customizable by using lists and the slice()
function.
Add the following variable declarations to variables.tf
.
Notice that the type for the list variables is list(string)
. Each element in these lists must be a string. List elements must all be the same type, but can be any type, including complex types like list(list)
and list(map)
.
Like lists and arrays used in most programming languages, you can refer to individual items in a list by index, starting with 0. Terraform also includes several functions that allow you to manipulate lists and other variable types.
Use the slice()
function to get a subset of these lists.
The Terraform console
command opens an interactive console that you can use to evaluate expressions in the context of your configuration. This can be very useful when working with and troubleshooting variable definitions.
Open a console with the terraform console
command.
Now use the Terraform console to inspect the list of private subnet blocks.
Refer to the variable by name to return the entire list.
Retrieve the second element from the list by index with square brackets.
Now use the slice()
function to return the first three elements from the list.
The slice()
function takes three arguments: the list to slice, the start index, and the end index (exclusive). It returns a new list with the specified elements copied ("sliced") from the original list.
Leave the console by typing exit
or pressing Control-D
.
Now update the VPC module configuration in main.tf
to use the slice function to extract a subset of the CIDR block lists for your public and private subnet configuration.
main.tf
This way, users of this configuration can specify the number of public and private subnets they want without worrying about defining CIDR blocks.
Each of the resources and modules declared in main.tf
includes two tags: project_name
and environment
. Assign these tags with a map
variable type.
Declare a new map
variable for resource tags in variables.tf
.
Setting the type to map(string)
tells Terraform to expect strings for the values in the map. Map keys are always strings. Like dictionaries or maps from programming languages, you can retrieve values from a map with the corresponding key. See how this works with the Terraform console.
Be sure to replace all five references to these hard-coded tags in your configuration.
Apply these changes. Once again, Terraform does not propose any changes since the default values of your variables match the original hard-coded values.
The lists and maps you used are collection types. Terraform also supports two structural types. Structural types have a fixed number of values that can be of different types.
Tuple: A fixed-length sequence of values of specified types.
Object: A lookup table, matching a fixed set of keys to values of specified types.
This configuration has a potential problem. AWS load balancers have naming restrictions. Load balancer names must be no more than 32 characters long, and can only contain a limited set of characters.
Now, use variable validation to restrict the possible values for the project and environment tags.
Replace your existing resource tags
variable in variables.tf
with the below code snippet, which includes validation blocks to enforce character limits and character sets on both project
and environment
values.
The regexall()
function takes a regular expression and a string to test it against, and returns a list of matches found in the string. In this case, the regular expression will match a string that contains anything other than a letter, number, or hyphen.
This ensures that the length of the load balancer name does not exceed 32 characters, or contain invalid characters. Using variable validation can be a good way to catch configuration errors early.
Apply this change to add validation to these two variables. There will be no changes to apply, since your infrastructure configuration has not changed.
Now test the validation rules by specifying an environment tag that is too long. Notice that the command will fail and return the error message specified in the validation block.