Terraform: Randomness as a Service

Native ways to create random values in your Terraform code!

Welcome to another Cloudblogger post ! Summer is heating up and we are searching ways to cool down, so grab a cool drink, and hop in today’s post about randomness and Terraform!

randomness: the quality or state of being or seeming random (as in lacking or seeming to lack a definite plan, purpose, or pattern)

https://www.merriam-webster.com/dictionary/randomness

It is a common issue when it comes to coding, particularly in Terraform, when we need to create our resources in Azure for example and just have a random string or number or both as a helper for naming.

Most deployments should have a persistent naming convention pattern ( have a look at this great post by @George Markou , Generate Resource Names using Bicep and Azure Naming Tool ), but there are cases where we want randomness. We need random names, strings , IDs or numbers and we prefer to have a standard block within Terraform to do that.

Well, look no further here are the random resources by Terraform to assist :

random_id (Resource)

The resource random_id generates random numbers that are intended to be used as unique identifiers for other resources.

This resource does use a cryptographic random number generator in order to minimize the chance of collisions, making the results of this resource when a 16-byte identifier is requested of equivalent uniqueness to a type-4 UUID.

This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.

Source: Terraform Documentation

Let’s have an example here with random_id.

main.tf

# Random ID
resource "random_id" "ran_id" {
  prefix = 'az-"
  byte_length = 4
}


resource "azurerm_resource_group" "rgroup" {
  name     = "rg-${random_id.ran_id.hex}"
  location = "North Europe"
}

Now when we apply we can see all the available Schema properties, and when we destroy we have an output of the values of the available properties since they have been applied into our configuration, regardless which one we actually used.

  # azurerm_resource_group.rgroup will be created
  + resource "azurerm_resource_group" "rgroup" {
      + id       = (known after apply)
      + location = "northeurope"
      + name     = (known after apply)
    }

  # random_id.ran_id will be created
  + resource "random_id" "ran_id" {
      + b64_std     = (known after apply)
      + b64_url     = (known after apply)
      + byte_length = 4
      + dec         = (known after apply)
      + hex         = (known after apply)
      + id          = (known after apply)
      + prefix      = "az-"
    }
  # azurerm_resource_group.rgroup will be destroyed
  - resource "azurerm_resource_group" "rgroup" {
      - id       = "/subscriptions/d33b3162-55d5-4c85-8ee7-b3ddd1a391ae/resourceGroups/rg-az-496aae9d" -> null
      - location = "northeurope" -> null
      - name     = "rg-az-496aae9d" -> null
      - tags     = {} -> null
    }

  # random_id.ran_id will be destroyed
  - resource "random_id" "ran_id" {
      - b64_std     = "az-SWqunQ==" -> null
      - b64_url     = "az-SWqunQ" -> null
      - byte_length = 4 -> null
      - dec         = "az-1231728285" -> null
      - hex         = "az-496aae9d" -> null
      - id          = "SWqunQ" -> null
      - prefix      = "az-" -> null
    }

There is also the keepers value available for random_id. The keepers value allows you to specify a set of key-value pairs that are used to uniquely identify a resource instance. When the values of the keepers are changed, Terraform will recreate the resource instance to reflect the new values.

Here’s an example of using keepers with an Azure resource:

locals {
  rg_location = "eastus"
}

resource "random_id" "rg_name" {
  length = 8
  prefix = "rg-"
}

resource "azurerm_resource_group" "example" {
  name     = random_id.rg_name.hex
  location = local.rg_location

  # Use keepers to identify the resource instance
  keepers = {
    rg_location = local.rg_location
  }
}

In this example, we’re using the keepers value to identify the azurerm_resource_group resource instance based on the rg_location variable. If the value of rg_location changes, Terraform will recreate the resource group to reflect the new location.

You can specify multiple key-value pairs in the keepers value to create a more complex identifier for the resource instance. For example, you could use a combination of region, environment, and application name to uniquely identify a resource instance.

random_integer (Resource)

The resource random_integer generates random values from a given range, described by the min and max attributes of a given resource.

This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.

Source: Terraform Documentation

The random_integer resource in Terraform can be used to generate a random integer within a specified range. This can be useful for generating unique IDs or other numeric values in your Terraform configuration. Here’s an example:

resource "random_integer" "example" {
  min = 100
  max = 999
}

output "random_number" {
  value = random_integer.example.result
}

In this example, we’re using the random_integer resource to generate a random integer between 100 and 999. We can then use the output block to display the generated integer. Each time you run terraform apply, the random_integer resource will generate a new random integer within the specified range.

You can customize the range of the generated integer by modifying the min and max values in the random_integer resource. You can also use the keepers value to trigger a recreate of the resource instance when certain values change, just like with the random_id resource.

random_password (Resource)

Identical to random_string with the exception that the result is treated as sensitive and, thus, not displayed in console output.

This resource does use a cryptographic random number generator.

Source: Terraform Documentation

resource "random_password" "example" {
  length = 16
  special = true
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_mysql_server" "example" {
  name                = "example-mysqlserver"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  administrator_login          = "mysqladminun"
  administrator_login_password = random_password.example.result # This is the password generated above

  sku_name   = "B_Gen5_2"
  storage_mb = 5120
  version    = "5.7"

  auto_grow_enabled                 = true
  backup_retention_days             = 7
  geo_redundant_backup_enabled      = true
  infrastructure_encryption_enabled = true
  public_network_access_enabled     = false
  ssl_enforcement_enabled           = true
  ssl_minimal_tls_version_enforced  = "TLS1_2"
}

resource "azurerm_mysql_configuration" "example" {
  name                = "interactive_timeout"
  resource_group_name = azurerm_resource_group.example.name
  server_name         = azurerm_mysql_server.example.name
  value               = "600"
}

In this example, we’re using the random_password resource to generate a random password string with a length of 16 characters and special characters included. We’re then using the result attribute of the random_password resource to set the administrator_password property of Azure MySQL.

This ensures that the password is unique and randomly generated!

random_pet (Resource)

The resource random_pet generates random pet names that are intended to be used as unique identifiers for other resources.

This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.

Source: Terraform Documentation

resource "random_pet" "example" {
  length = 2 # Number of words that for the Pet Name
  prefix = "rg-"  # A prefix can be set as well
}

resource "azurerm_resource_group" "rgdemo" {
  name     = "${random_pet.example.id}"
  location = "northeurope"
}

Quite useful randomness for Dev/Test deployments to have quick and consistent strings for naming our resources. As we can see the resource has a separator default to “-“.

# azurerm_resource_group.rgdemo will be destroyed
  - resource "azurerm_resource_group" "rgdemo" {
      - id       = "/subscriptions/d33b3162-55d5-4c85-8ee7-b3ddd1a391ae/resourceGroups/rg-willing-python" -> null
      - location = "northeurope" -> null
      - name     = "rg-willing-python" -> null
      - tags     = {} -> null
    }

  # random_pet.example will be destroyed
  - resource "random_pet" "example" {
      - id        = "rg-willing-python" -> null
      - length    = 2 -> null
      - prefix    = "rg" -> null
      - separator = "-" -> null
    }

We can customize the length of the generated pet name by modifying the length value in the random_pet resource. We can also use the keepers value to trigger a recreate of the resource instance when certain values change, just like with the random_id and random_integer resources.

random_shuffle (Resource)

The resource random_shuffle generates a random permutation of a list of strings given as an argument.

Source: Terraform Documentation

The random_shuffle resource in Terraform can be used to shuffle a list of values and select a random subset of those values. Here’s an example of using random_shuffle with Azure availability zones:

variable "zones" {
  default = ["1", "2", "3"]
}

resource "random_shuffle" "example" {
  input = var.zones
}

resource "azurerm_availability_set" "example" {
  name                = "example-as"
  location            = "eastus"
  resource_group_name = "example-rg"
  managed             = true
  platform_update_domain_count = 5
  platform_fault_domain_count = 3
  availability_zone = slice(random_shuffle.example.result, 0, 2)
}

In this example, we’re using the random_shuffle resource to shuffle the list of availability zones specified in the zones variable, and then select a random subset of two zones. We’re then using the slice function to select the first two values from the shuffled list, and using those values as the availability_zone property for the azurerm_availability_set resource.

This ensures that the availability zones for the availability set are randomly selected each time the Terraform configuration is applied, which can help distribute your resources across multiple zones for increased availability.

You can modify the input value in the random_shuffle resource to specify a different list of values to shuffle. You can also modify the slice function to select a different number of values from the shuffled list.

random_string (Resource)

The resource random_string generates a random permutation of alphanumeric characters and optionally special characters.

This resource does use a cryptographic random number generator.

Historically this resource’s intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use random_id, for sensitive random values please use random_password.

Source: Terraform Documentation

The random_string is useful when we need random strings, especially with resources which need unique names. It has various control elements on the created string such as :

resource "random_string" "example" {
  length  = 12
  special = true
}

resource "azurerm_storage_account" "example" {
  name                     = "example${random_string.example.result}"
  resource_group_name      = "example-rg"
  location                 = "eastus"
  account_tier             = "Standard"
  account_replication_type = "GRS"
}

In this example, we’re using the random_string resource to generate a random string of 12 characters with special characters included. We’re then using the result attribute of the random_string resource to append the generated string to the storage account name. This ensures that the storage account name is unique and doesn’t conflict with any existing storage accounts in the same Azure region.

random_uuid (Resource)

The resource random_uuid generates random uuid string that is intended to be used as unique identifiers for other resources.

This resource uses hashicorp/go-uuid to generate a UUID-formatted string for use with services needed a unique string identifier.

Source: Terraform Documentation

The random_uuid resource in Terraform can be used to generate a random UUID (Universally Unique Identifier) string. UUIDs are designed to be unique across space and time, making them useful for generating unique IDs for resources in your Terraform configuration.

resource "random_uuid" "example" {
  keepers = {
    app_name = "example-app"
  }
}

resource "azurerm_storage_account" "example" {
  name                     = "example${random_uuid.example.result}"
  resource_group_name      = "example-rg"
  location                 = "eastus"
  account_tier             = "Standard"
  account_replication_type = "GRS"
}

In this example, we’re using the random_uuid resource to generate a random UUID string. We’re then using the result attribute of the random_uuid resource to append the generated UUID to the storage account name. This ensures that the storage account name is unique and doesn’t conflict with any existing storage accounts in the same Azure region.

We’re also using the keepers value to identify the random_uuid resource instance based on the app_name value. This means that if the value of app_name changes, Terraform will recreate the random_uuid resource instance to reflect the new value.

You can use the keepers value to trigger a recreate of the resource instance when certain values change, just like with the random_id, random_integer, random_pet, and random_string resources.

Conclusion

Random resources in Terraform provide a powerful way to generate unique values for resources in your infrastructure. By using these resources, you can ensure that your resource names, IDs, and other properties are unique and don’t conflict with existing resources.

Terraform provides several built-in random resources, including random_id, random_integer, random_pet, random_string, random_uuid, and random_shuffle. Each of these resources has specific use cases and can be customized to fit your needs.

We can use random_id to generate a random ID for a resource, random_integer to generate a random integer value, random_pet to generate a random name, random_string to generate a random string, random_uuid to generate a random UUID, and random_shuffle to shuffle a list of values and select a random subset.

We can also use the keepers value to trigger a recreate of the resource instance when certain values change, ensuring that your resources remain unique even as your infrastructure evolves.

terraform {
  required_providers {
    random = {
      source = "hashicorp/random"
      version = "3.5.1"
    }
  }
}

provider "random" {
  # Configuration options
}

Spread the word. Share this post!

Leave Comment