Actions

Azure/Terraform

From Ever changing code

< Azure

Store Terraform state in Azure Storage

Create blob storage

export ARM_SUBSCRIPTION=aabbccdd-1122-11aa22bb3-11aa22bb33cc

#!/bin/bash

RESOURCE_GROUP_NAME=tfstate
STORAGE_ACCOUNT_NAME=tfstate${ARM_SUBSCRIPTION::8}
CONTAINER_NAME=tfstate
REGION=eastus

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

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

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

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

echo "storage_account_name: $STORAGE_ACCOUNT_NAME"
echo "container_name: $CONTAINER_NAME"
echo "access_key: $ACCOUNT_KEY"

azurerm backend config

terraform {
  required_version = "= 0.11.11"
# backend "local"   {}
  backend "azurerm" {
#                           tfstate<Subscription8chars>
    storage_account_name = "tfstate01234567" #only lowercase letters nad numbers unique across Azure
    container_name       = "infrarg"         #only lowercase letters and numbers
    key                  = "tfstate"         #state file name, when delimited with '/' will create a folder aka prefix in AWS
#   key                  = "stack/tfstate"
#   access_key           = "ARM_ACCESS_KEY"  #optional access_key in plain text it's advised to export variable
  }
}


Configure azurerm backend via terraform init. When you auth via:

  • key - it's storage account token, nothing else is required
  • Service Principal - you need to pass a resource group name provide ARM_client_id and ARM_client_secret credentials by explicitly in backend {} block or export them as environment variable.
terraform init -input=false \                                                                       
               -backend=true \                                                                      
               -backend-config="resource_group_name=${LOCATION_STATE_STORAGE_RESOURCE_GROUP_NAME}" \
               -backend-config="storage_account_name=${LOCATION_STATE_STORAGE_ACCOUNT}" \           
               -backend-config="container_name=${LOCATION_STATE_STORAGE_CONTAINER}" \               
               -backend-config="key=${LOCATION_STATE_KEY}"


Using the key argument like in s3 backend you can store state files in hierarchy structure. Eg:

# High Level View
# https://<storage_account>.blob.core.windows.net/<container>/<key/tfstate>
# https://infrarg.blob.core.windows.net/tfstate/tfstate(state_file)
# https://infrarg.blob.core.windows.net/tfstate/stack  (folder)/terraform.tfstate(state_file)
# https://infrarg.blob.core.windows.net/tfstate/storage(folder)/terraform.tfstate(state_file)


Example changing state from local to azurerm. Note Previous and New temporarly saved state files.

Initializing the backend...
Backend configuration changed!

Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.

Terraform detected that the backend type changed from "local" to "azurerm".
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "azurerm" backend. An existing non-empty state already exists in
  the new backend. The two states have been saved to temporary files that will be
  removed after responding to this query.

  Previous (type "local"): /tmp/terraform962571048/1-local.tfstate
  New      (type "azurerm"): /tmp/terraform962571048/2-azurerm.tfstate

  Do you want to overwrite the state in the new backend with the previous state?
  Enter "yes" to copy and "no" to start with the existing state in the newly
  configured "azurerm" backend.

  Enter a value: yes

Releasing state lock. This may take a few moments...

Successfully configured the backend "azurerm"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...

Terraform has been successfully initialized!


Key notes:

  • you must create resource_group and storage_account before migrating backend
  • both container and full prefixed path aka folders will be created when needed
  • when moving backend temporarly remove -input=false from <terraform init</code> command

References