Terraform and Azure (Infrastructure as Code) – Part 3

Part 1 of this series looked at setting up Terraform for use with Azure and then deploying some infrastructure. Part 2 looked at changing Azure subscriptions, inserting an SSH key in virtual machines and making the virtual machine run commands at creation.

Backend Storage

When I discussed using Terrform with AWS I made a blog post about the state file and storing it remotely. To quickly recap here is briefly what I wrote previously:

“The .tfstate file records the state of the infrastructure Terraform is managing so that Terraform knows what has been created, what is running and when changes are made where the changes will effect. If two or more team members are working with the same .tfstate file and each trying to write to it then problems will occur.”

GeekTechStuff

That issue is not unique to AWS and can occur whenever multiple people are working on the same Terraform code. As with AWS, Azure too has a solution for storing the .tfstate file remotely.

Within Azure we can store the .tfstate file within Azure blob storage, which can be created from the Azure CLI. Microsoft has documentation for this process.

#!/bin/bash

RESOURCE_GROUP_NAME=tfstate
STORAGE_ACCOUNT_NAME=geektechstufftfstorage
CONTAINER_NAME=projectnameheretfstates

# 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

The STORAGE_ACCOUNT_NAME has to be globally unique (i.e. unique across all of Azure). The CONTAINER_NAME will be the bit holding the .tfstate file, so will probably change for each Terraform project (i.e. same STORAGE_ACCOUNT for each project but a different CONTAINER_NAME for each).

Note: The Azure blob will have public access – make sure you place appropriate security controls around the access.

For Terraform to access the container we can set an environment variable in the Powershell where Terraform is run from:

$RESOURCE_GROUP_NAME=tfstate
$STORAGE_ACCOUNT_NAME=geektechstufftfstorage

$ACCOUNT_KEY=(Get-AzStorageAccountKey -ResourceGroupName $RESOURCE_GROUP_NAME -Name $STORAGE_ACCOUNT_NAME)[0].value
$env:ARM_ACCESS_KEY=$ACCOUNT_KEY

Terraform now needs to be configured to use the container for storage. Within the main.tf a new section needs adding to the initial terraform block which originally looked like this:

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

The section that needs adding is:

backend "azurerm" {
    resource_group = "RESOURCE_GROUP_NAME_HERE"
    storage_account_name = "STORAGE_ACCOUNT_NAME_HERE"
    container_name = "CONTAINER_NAME_HERE"
    key = "terraform.tfstate"
}

Once the section above has been added the terraform block should look like:

terraform {
    required_providers {
        azurerm = {
            source = "hashicorp/azurerm"
            version = "~>2.40.0"
            }
        }
    backend "azurerm" {
        resource_group = "RESOURCE_GROUP_NAME_HERE"
        storage_account_name = "STORAGE_ACCOUNT_NAME_HERE"
        container_name = "CONTAINER_NAME_HERE"
        key = "terraform.tfstate"
        }    
    }

Save main.tf and run the terraform init command to tell Terraform to use the new backend storage.