Jeff Brown

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

So you’ve been learning and practicing deploying infrastructure with Terraform. Initially, you might not worry about your state file being local on your system. However, as you start deploying resources for real environments, you might need to move your Terraform state to a remote location, like an Azure Storage Account.

This tutorial will walk you through how to move your local Terraform state file to an Azure Storage Account. For this tutorial, you will need:

  • An Azure subscription and enough permissions to create resources, like Owner or Contributor
  • Terraform installed. This tutorial uses version 1.0.0.
  • Azure CLI installed. This tutorial uses version 2.25.0 and PowerShell version 7.1.3.

Viewing Current Local Terraform State

To get started, examine the Terraform configuration file below. The configuration creates a resource group, a virtual network, and a subnet.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.64.0"
    }
  }
}

provider "azurerm" {
  features {}
}

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

resource "azurerm_virtual_network" "vnet" {
  name                = "vnet-prod-westus2"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  address_space       = ["10.220.0.0/16"]
  subnet {
    name           = "subnet1"
    address_prefix = "10.220.1.0/24"
  }
}

If you deploy this configuration, you should see a file named terraform.tfstate in the same directory as the configuration file. Terraform tracks the creation and manipulation of resources using this state file. Each resource in your configuration creates an entry in the state that contains resource metadata in key-value pairs.

For example, here is a snippet of the state file for the above configuration:

Viewing local Terraform state file
Viewing a Terraform state file

However, having the Terraform state file local limits who can update the deployed resources. No one else can easily deploy the same configuration without access to the state file. HashiCorp recommends storing the state file in a remote location for better team collaboration. One option is to store the state file in an Azure Storage Account.

Migrating Terraform State to Azure Storage Account

The process to migrate your local Terraform state file can be accomplished in 3 steps. Before getting started, log in to your Azure account using the Azure CLI command az login. If necessary, select the Azure subscription where you will deploy the storage account using the az account set command.

Create a Storage Account

First, set some variables to name the Resource Account, Storage Account, and container. The Storage Account contains a randomly generated number to make the name globally unique in Azure. The container name should reflect the environment and resources the Terraform configuration deploys.

Note: Be sure to store the state in its own Resource Group and Storage Account. If you use a Storage Account that is used for other purposes, you may accidentally delete the Storage Account and remove the state file.

In this case, the Terraform configuration deploys a virtual network, so the container name is prodnetwork. You can use the same Storage Account to store multiple Terraform state files as long as each file is in its own container.

$rgName = 'terraformstate-rg'
$random = Get-Random -Minimum 10000 -Maximum 99999
$saName = "terraformstate$random"
$containerName = 'prodnetwork'

Next, use the az group create and the az storage account create commands to create the Resource Account and Storage Account. This example deploys the resources to the WestUs2 Azure region, but you can pick any region closest to you. The Storage Account will have blob public access disabled.

With the storage account created, use the az storage container create command to create the container for storing this configuration’s state file.

# Create Azure Resource Group
az group create `
    --name $rgName `
    --location westus2

# Create Storage Account with public access disabled
az storage account create `
    --resource-group $rgName `
    --name $saName `
    --sku Standard_LRS `
    --allow-blob-public-access $false

# Create container to store configuration state file
az storage container create `
    --name $containerName `
    --account-name $saName

With all the elements in place, you also need one of the Storage Accounts’ access keys. The access key allows Terraform to authenticate to the storage account and perform actions, like creating files. Use the az storage account keys list command to list both of the access keys. You can use either key value for the Terraform configuration.

# List Storage Account access keys
az storage account keys list `
    --resource-group $rgName `
    --account-name $saName
Listing Azure Storage Account access keys
List Storage Account access keys

Update Terraform Configuration

In your Terraform configuration (typically main.tf), add the information about where Terraform should store the state file. This configuration is written in the terraform { } block using the keyword backend along with azurerm since Azure will host the state file.

In the backend configuration, you need to specify some additional information so Terraform knows where to store the state file. These values should match the resources you created in the previous section.

  • resource_group_name: The name of the Resource Group hosting the Storage Account for storing the remote state file
  • storage_account_name: The name of the Storage Account to host the state file
  • container_name: The name of the container to store the state file.
  • key: The name of the Terraform state file, ending with .tfstate.

Terraform also needs to authenticate to the Storage Account and container to perform the necessary reads and writes to the state file. One way is to add the access_key property to the configuration. Here is the updated configuration with the Azure back end information.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.64.0"
    }
  }

  backend "azurerm" {
    resource_group_name  = "terraformstate-rg"
    storage_account_name = "terraformstate35398"
    container_name       = "networkprod"
    key                  = "terraform.tfstate"
    access_key           = "ivowJtGlZMCh6SiaSP+QucyRFpP49VN2oyCapJaLf9dBmP39LGUVzTKNxARo01bd+sGWbyajoSE4sZ8eqqG4nQ=="
  }
}

However, storing the access key in the configuration file is not ideal as it exposes credentials and writes the access key to the disk. Alternatively, you can remove the access_key property and store the access key in an environment variable named ARM_ACCESS_KEY. Terraform is programmed to look for this environment variable in the absence of the value in the configuration file.

To save an environment variable in PowerShell, use the $env: prefix followed by ARM_ACCESS_KEY. For example:

$env:ARM_ACCESS_KEY = "<access key>"

Move the Terraform State

Once the storage account is created and the Terraform configuration updated, you run terraform init to prompt Terraform to update the state file location. Terraform recognizes that a local pre-existing state was found, but no existing state was found in the new backend. Therefore, Terraform prompts to copy the existing, so enter “yes” to copy the state. Alternatively, you can enter “no” to start with an empty state.

To verify the move is successful, run terraform plan again to see if any changes are needed in infrastructure in comparison to the configuration. There should be no to minimal changes. Also, the local terraform.tfstate file should now be empty.

# Initialize configuration to prompt moving remote state
terraform init

# Run plan to confirm any infrastructure changes
terraform plan
Running terraform init to move the state file to Azure
Moving Terraform state using the init command
Running terraform plan post state file move
Running Terraform plan to verify any configuration changes

If you navigate to the Storage Account and container in the Azure, you should see the terraform.tfstate file (or whatever you named in the key in the configuration).

Verify Terraform state file in Azure storage account
Verify state file stored in Azure Storage Account

Summary

In this tutorial, you learned how to move the Terraform state file to a Storage Account in Azure. The Terraform state file is the source of truth for the Terraform configuration and deployment. While using a local state file is fine for learning and testing, you should develop a plan to manage remote state files. Having a remote state file is good for team collaboration as well as truly performing infrastructure-as-code inside an automated CI/CD pipeline for infrastructure deployments.

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

Leave a Reply