Jeff Brown

Cloud and DevOps Engineer specializing in Microsoft 365, Azure, and PowerShell. Twitter | LinkedIn

One criticism of Azure ARM templates is the requirement that you manually create resource dependencies. This process can be tedious and frustrating for new administrators learning the language. But you’re in luck! Terraform manages these resource dependencies for you automatically.

In this post, you’ll learn about the different types of Terraform resource dependencies and what happens during a deployment if you incorrectly define resources.

Types of Terraform Resource Dependencies

Terraform has two ways of managing resource dependencies: using implicit using resource names and explicit using the depends_on module.

Implicit Dependencies

You create an implicit dependency when you reference a resource or module in another resource. For example, let’s say you are creating an Azure resource group and a storage account. You need the resource group first before creating the resource group.

You create an implicit dependency when you reference a resource in another resource using the symbolic name. The symbolic name is a reference to the resource but is not the actual name of the resource. In the example below, names like “rg” and “sa” refer to the resource group and storage account respectively but are not the actual names of the resources.

Take a look at the example Terraform configuration below. The code creates a resource group named tfdepends-rg, and the resource group will have a storage account named jbtterraformdemo. Since the storage account requires Terraform to create the resource group first, you create an implicit dependency by referencing the resource group resource. Terraform and the Azure resource provider determines these dependencies based on the configuration.

When referencing another resource in the Terraform configuration, use the resource type and resource (symbolic) name. The combination of these two creates a unique identifier in the Terraform configuration. For example, in the storage account definition, the example references the defined resource group on lines 21 and 22. Using the unique resource ID, you can also reference the resource group’s properties, like name and location.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=2.61.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "tfdepends-rg"
  location = "westus2"
}

resource "azurerm_storage_account" "sa" {
  name                     = "jbtterraformdemo"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_kind             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

Because the storage account configuration references the resource group, Terraform now knows to create the resource group first, then the storage account. You can see the resource order when applying the Terraform configuration. The resource group is created first, then the storage account.

Note: The resource order in the Terraform configuration file does not determine the resource order creation. In the above example, you could put the storage account definition first followed by the resource group. It is the resource reference that determines the creation order, not the written out order.

Explicit Dependencies

Explicit dependencies are dependencies you create when defining a resource. You use the depends_on argument when Terraform can’t automatically determine a dependency. Explicit dependencies are only necessary when a resource or module relies on another resource’s behavior but can’t access that resource’s data.

While not required, modify the storage account in the previous example and create a dependency on the resource group. Any resource can have a depends_on argument as part of its definition. The dependency is a list of resources the definition depends on. As you can see on line 8, this dependency is the resource type and resource symbolic name.

resource "azurerm_storage_account" "sa" {
  name                     = "jbtterraformdemo"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_kind             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
  depends_on               = [azurerm_resource_group.rg]
}

Defining explicit dependencies should only be used as a last resort. As a best practice, include a comment as to why the resource requires the dependency for future code maintainers.

Encountering Terraform Resource Dependency Errors

Implicit dependencies rely on using the resource type and symbolic name when defining other resources. When defining resources, you may be tempted to hard-code values, like a resource group name. Terraform can run into a problem determining order creation if you hard-code a resource value and cause an error.

Let’s take a look at an example. Instead of referencing the resource group in the storage account definition, enter the name of the resource group and location as strings. Here is a snippet of the configuration with the modified storage account resource properties on lines 3 & 4.

resource "azurerm_storage_account" "sa" {
  name                     = "jbtterraformdemo"
  resource_group_name      = "tfdepends-rg"
  location                 = "westus2"
  account_kind             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

Terraform does not know that the storage account depends on the resource group (despite the storage account referencing the exact name of the resource group). Therefore, Terraform tries to create both resources at the same time. Unfortunately, Terraform runs into an error saying it cannot create the storage account as the resource group doesn’t exist.

Terrform apply error without resource dependencies
Terrform apply error without resource dependency

The same principle applies when using variables in the configuration. If you use a variable for the resource group name, don’t use the variable reference in any resource that depends on the resource group. A configuration file like this experiences the same failure. Note line 12 that references the resource group variable name instead of the resource type and symbolic name.

variable "rg_name" {
  type = string
}

resource "azurerm_resource_group" "rg" {
  name     = var.rg_name
  location = "westus2"
}

resource "azurerm_storage_account" "sa" {
  name                     = "jbtterraformdemo"
  resource_group_name      = var.rg_name
  location                 = "westus2"
  account_kind             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

Summary

Terraform is great in that you don’t need to define resource dependencies. As long as you define the resources correctly, Terraform will manage the creation order for you. However, if you try to use real or variable values when a dependency is required, you will run into issues.

Enjoyed this content? Check out more of my Terraform articles!

This Post Has 2 Comments

Start a discussion!