Store Terraform state in Azure Storage

Terraform enables the definition, preview, and deployment of cloud infrastructure. Using Terraform, you create configuration files using HCL syntax. The HCL syntax allows you to specify the cloud provider - such as Azure - and the elements that make up your cloud infrastructure. After you create your configuration files, you create an execution plan that allows you to preview your infrastructure changes before they're deployed. Once you verify the changes, you apply the execution plan to deploy the infrastructure.

Terraform state is used to reconcile deployed resources with Terraform configurations. State allows Terraform to know what Azure resources to add, update, or delete.

By default, Terraform state is stored locally, which isn't ideal for the following reasons:

  • Local state doesn't work well in a team or collaborative environment.
  • Terraform state can include sensitive information.
  • Storing state locally increases the chance of inadvertent deletion.

In this article, you learn how to:

  • Create an Azure storage account
  • Use Azure storage to store remote Terraform state.
  • Understand state locking
  • Understand encryption at rest

1. Configure your environment

  • Azure subscription: If you don't have an Azure subscription, create a free account before you begin.

2. Configure remote state storage account

Before you use Azure Storage as a backend, you must create a storage account.

Run the following commands or configuration to create an Azure storage account and container:

#!/bin/bash

RESOURCE_GROUP_NAME=tfstate
STORAGE_ACCOUNT_NAME=tfstate$RANDOM
CONTAINER_NAME=tfstate

# Create resource group
az group create --name $RESOURCE_GROUP_NAME --location eastus

# Create storage account
az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob

# Create blob container
az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME

Key points:

  • Azure storage accounts require a globally unique name. To learn more about troubleshooting storage account names, see Resolve errors for storage account names.
  • Terraform state is stored in plain text and may contain secrets. If the state is incorrectly secured, unauthorized access to systems and data loss can result.
  • In this example, Terraform authenticates to the Azure storage account using an Access Key. In a production deployment, it's recommended to evaluate the available authentication options supported by the azurerm backend and to use the most secure option for your use case.
  • In this example, public network access is allowed to this Azure storage account. In a production deployment, it's recommended to restrict access to this storage account using a storage firewall, service endpoint, or private endpoint.

3. Configure terraform backend state

To configure the backend state, you need the following Azure storage information:

  • storage_account_name: The name of the Azure Storage account.
  • container_name: The name of the blob container.
  • key: The name of the state store file to be created.
  • access_key: The storage access key.

Each of these values can be specified in the Terraform configuration file or on the command line. We recommend that you use an environment variable for the access_key value. Using an environment variable prevents the key from being written to disk.

Run the following commands to get the storage access key and store it as an environment variable:

ACCOUNT_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
export ARM_ACCESS_KEY=$ACCOUNT_KEY

Key points:

  • To further protect the Azure Storage account access key, store it in Azure Key Vault. The environment variable can then be set by using a command similar to the following. For more information on Azure Key Vault, see the Azure Key Vault documentation.

    export ARM_ACCESS_KEY=$(az keyvault secret show --name terraform-backend-key --vault-name myKeyVault --query value -o tsv)
    

Create a Terraform configuration with a backend configuration block.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
  }
  backend "azurerm" {
      resource_group_name  = "tfstate"
      storage_account_name = "<storage_account_name>"
      container_name       = "tfstate"
      key                  = "terraform.tfstate"
  }

}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "state-demo-secure" {
  name     = "state-demo"
  location = "eastus"
}

Replace <storage_account_name> with the name of your Azure storage account.

Run the following command to initialize the configuration:

terraform init

Run the following command to run the configuration:

terraform apply

You can now find the state file in the Azure Storage blob.

4. Understand state locking

Azure Storage blobs are automatically locked before any operation that writes state. This pattern prevents concurrent state operations, which can cause corruption.

For more information, see State locking in the Terraform documentation.

You can see the lock when you examine the blob through the Azure portal or other Azure management tooling.

Azure blob with lock

5. Understand encryption-at-rest

Data stored in an Azure blob is encrypted before being persisted. When needed, Terraform retrieves the state from the backend and stores it in local memory. If you use this pattern, state is never written to your local disk.

For more information on Azure Storage encryption, see Azure Storage service encryption for data at rest.

Troubleshoot Terraform on Azure

Troubleshoot common problems when using Terraform on Azure

Next steps