How to use If-Else in Terraform

Having been writing alot recently on if, else in various tools I use, and now it’s time to explore what Terraform brings to the table. As with any Infrastructure as Code (IaC) solution, there often comes a need to incorporate logic and conditionals into your configurations, enabling you to make choices based on specific criteria.

In this blog post, we’ll dive into Terraform’s capabilities for incorporating conditional logic, covering some popular techniques such as conditional expressions, the ‘count’ parameter, and the powerful ‘dynamic’ blocks.

Conditional Expressions

One of the most common ways to implement if-else logic in Terraform is through conditional expressions. These expressions are straightforward but incredibly versatile. With the standard approach:

condition ? true_value : false_value

With this meaning, if the condition is true, return true_value and if false, return false_value

Lets break this down with an example. Imagine we have a variable environment, and we want to determine if it equals production The conditional expression would look like this:

var.environment == "production" ? true : false

With the above, if var.environment is equal to production, then the value is true – or return false. Using conditional expressions, it allow you to choose between different values or configurations based on a condition.

Now consider the below scenario:

variable "environment" {
  type    = string
  default = "staging"
}

resource "azurerm_resource_group" "rg" {
  name     = "tamops-resources"
  location = "Uk South"
}

resource "azurerm_storage_account" "sa" {
  name                     = "tamopssa"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = var.environment == "production" ? "GRS" :"LRS"
}

Passing in the variable environment as staging will set the storage account replication type to LRS, only configure GRS when the variable environment is production. A great way to save some costs and only give your Production environment the more premium features.

Running the above with environment variable set to staging we can see from the plan, it will set replication type to LRS

  + resource "azurerm_storage_account" "sa" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "LRS"

Now setting the same variable to production – replication type will change to GRS

  + resource "azurerm_storage_account" "sa" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "GRS"

Terraform example here on GitHub of the above

The “count” parameter

Terraform’s count parameter offers a straightforward way to conditionally manage resource creation. It’s essentially a numerical value that determines how many instances of a resource to create. This can be highly useful when you need to create or destroy resources based on specific conditions.

An example below showing count in use:

variable "sa_create" {
  type    = bool
  default = "true"
}

resource "azurerm_resource_group" "rg" {
  name     = "tamops-resources"
  location = "Uk South"
}

resource "azurerm_storage_account" "sa" {
  count                    = var.sa_create ? 1 : 0
  name                     = "tamopssa"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

In this example, if the sa_create variable is set to true, Terraform will create one Azure Storage account.

  # azurerm_storage_account.sa[0] will be created

If it’s set to false, the count will be zero, and no instances will be created.

  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "uksouth"
      + name     = "rg-resources"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The “count” parameter is a straightforward way to conditionally manage resource creation, but it may not cover all scenarios.

Terraform example here on GitHub of the above

Conditional Configuration with “dynamic” Blocks

Terraform takes it a step further by providing the flexibility to conditionally configure resources using ‘dynamic’ blocks. This feature shines when you need to configure resource properties in a more dynamic and adaptable manner. ‘Dynamic’ blocks enable the creation of multiple instances of a block, each with its unique configuration. This proves invaluable when you’re tasked with creating numerous resources that share common settings but require different values.

Lets look at an example of using a dynamic block, the below example makes use of a dynamic block with storage accounts

resource "azurerm_resource_group" "rg" {
  name     = "rg-resources"
  location = "Uk South"
}

locals {
  storage_accounts = [
    {
      name        = "thomassa1"
      access_tier = "Hot"
    },
    {
      name        = "thomassa2"
      access_tier = "Cool"
    }
  ]
}

resource "azurerm_storage_account" "example" {
  for_each = { for sa in local.storage_accounts : sa.name => sa }

  name                     = each.value.name
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  dynamic "network_rules" {
    for_each = each.value.access_tier == "Hot" ? [1] : []

    content {
      default_action = "Deny"
      ip_rules       = ["23.45.1.0/30"]
    }
  }
}

In this example, we define a local variable storage_accounts that contains a list of storage account configurations. We then use a dynamic block to create multiple instances of the azurerm_storage_account resource, one for each storage account configuration.

The for_each argument in the azurerm_storage_account resource creates an instance of the resource for each element in the storage_accounts list. The name and access_tier attributes are set based on the values in the storage_accounts list.

The dynamic block creates an instance of the network_rules block only if the access_tier is set to “Hot”. This allows us to conditionally create the network_rules block based on the value of the access_tier attribute.

Looking at a snippet from example plan, we can see network_rules only being applied to thomassa1 storage account

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "uksouth"
      + name     = "rg-resources"
    }

  # azurerm_storage_account.example["thomassa1"] will be created
  + resource "azurerm_storage_account" "example" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "LRS"
      + account_tier                      = "Standard"
      + network_rules {
          + bypass                     = (known after apply)
          + default_action             = "Deny"
          + ip_rules                   = [
              + "23.45.1.0/30",
            ]
          + virtual_network_subnet_ids = (known after apply)
        }
    }

  # azurerm_storage_account.example["thomassa2"] will be created
  + resource "azurerm_storage_account" "example" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "LRS"
      + account_tier                      = "Standard"
    }

Plan: 3 to add, 0 to change, 0 to destroy.

As you continue your journey with Terraform and Azure, you’ll find that dynamic blocks can be a powerful tool in your infrastructure provisioning toolkit. They streamline your Terraform configurations while accommodating diverse resource requirements.

Terraform example here on GitHub of the above

Finishing up

In conclusion, conditional logic in Terraform is a valuable feature that empowers you to build dynamic and adaptable infrastructure configurations. Whether you’re making choices between different resource types, configuring resource properties based on conditions, or managing resource creation, Terraform equips you with a variety of tools, including count parameters, conditional expressions, and dynamic blocks. Mastery of these techniques will help you create versatile and efficient infrastructure code.

1 comment

Leave a Reply