
How to Create an Azure Remote Backend for Terraform
For simple test scripts or for development, a local state file will work. However, if we are working in a team, deploying our infrastructure from a CI/CD tool or developing a Terraform using multiple layers, we need to store the state file in a remote backend and lock the file to avoid mistakes or damage the existing infrastructure.
We can use remote backends, such as Azure Storage, Google Cloud Storage, Amazon S3, and HashiCorp Terraform Cloud & Terraform Enterprise, to keep our files safe and share between multiple users.
In this story, we will take a look at a step by step procedure to use Microsoft Azure Storage to create a Remote Backend for Terraform using Azure CLI, PowerShell, and Terraform.
1. Creating a Service Principal and a Client Secret
Using a Service Principal, also known as SPN, is a best practice for DevOps or CI/CD environments and is one of the most popular ways to set up a remote backend and later move to CI/CD, such as Azure DevOps.
First, we need to authenticate to Azure. To authenticate using Azure CLI, we type:
az loginThe process will launch the browser and after the authentication is complete we are ready to go.

We will use the following command to get the list of Azure subscriptions:
az account list --output tableWe can select the subscription using the following command (both subscription id and subscription name are accepted):
az account set --subscription <Azure-SubscriptionId>Then create the service principal account using the following command:
az ad sp create-for-rbac --role="Contributor"
--scopes="/subscriptions/SUBSCRIPTION_ID"This is the result:

Note: as an option, we can add the -name parameter to add a descriptive name.
az ad sp create-for-rbac --role="Contributor"
--scopes="/subscriptions/SUBSCRIPTION_ID" --name="Azure-DevOps"These values will be mapped to these Terraform variables:
- appId (Azure) → client_id (Terraform).
- password (Azure) → client_secret (Terraform).
- tenant (Azure) → tenant_id (Terraform).
2. Configuring the Remote Backend to use Azure Storage in Azure CLI
We will execute the following Azure CLI script to create the storage account in Azure Storage in Bash or Azure Cloud Shell:
RESOURCE_GROUP_NAME=kopicloud-tstate-rg
STORAGE_ACCOUNT_NAME=kopicloudtfstate$RANDOM
CONTAINER_NAME=tfstate# Create resource group
az group create --name $RESOURCE_GROUP_NAME --location "West Europe"# 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"3. Configuring the Remote Backend to use Azure Storage with PowerShell
We will execute the following Azure PowerShell script to create the storage account in Azure Storage:
# Variables
$azureSubscriptionId = "9c242362-6776-47d9-9db9-2aab2449703"
$resourceGroup = "kopicloud-tstate-rg"
$location = "westeurope"
$random = -join ((0..9) | Get-Random -Count 5 | % {$_})
$accountName = "kopicloudtfstate" + $random
$containerName = "tfstate"# Set Default Subscription
Select-AzSubscription -SubscriptionId $azureSubscriptionId# Create Resource Group
New-AzResourceGroup -Name $resourceGroup -Location $location -Force# Create Storage Account
$storageAccount = New-AzStorageAccount `
-ResourceGroupName $resourceGroup `
-Name $accountName `
-Location $location `
-SkuName Standard_RAGRS `
-Kind StorageV2
# Get Storage Account Key
$storageKey = (Get-AzStorageAccountKey `
-ResourceGroupName $resourceGroup `
-Name $accountName).Value[0]# Create Storage Container
$ctx = $storageAccount.Context
$container = New-AzStorageContainer `
-Name $containerName `
-Context $ctx -Permission blob# Results
Write-Host
Write-Host ("Storage Account Name: " + $accountName)
Write-Host ("Container Name: " + $container.Name)
Write-Host ("Access Key: " + $storageKey)This is the result:

4. Configuring the Remote Backend to use Azure Storage with Terraform
We can also use Terraform to create the storage account in Azure Storage.
We will start creating a file called az-remote-backend-variables.tf and adding this code:
# company
variable "company" {
type = string
description = "This variable defines the name of the company"
}# environment
variable "environment" {
type = string
description = "This variable defines the environment to be built"
}# azure region
variable "location" {
type = string
description = "Azure region where the resource group will be created"
default = "north europe"
}Then we create the az-remote-backend-main.tf file that will configure the storage account:
# Generate a random storage name
resource "random_string" "tf-name" {
length = 8
upper = false
number = true
lower = true
special = false
}# Create a Resource Group for the Terraform State File
resource "azurerm_resource_group" "state-rg" {
name = "${lower(var.company)}-tfstate-rg"
location = var.location lifecycle {
prevent_destroy = true
}
tags = {
environment = var.environment
}
}# Create a Storage Account for the Terraform State File
resource "azurerm_storage_account" "state-sta" {
depends_on = [azurerm_resource_group.state-rg]
name = "${lower(var.company)}tf${random_string.tf-name.result}"
resource_group_name = azurerm_resource_group.state-rg.name
location = azurerm_resource_group.state-rg.location
account_kind = "StorageV2"
account_tier = "Standard"
access_tier = "Hot"
account_replication_type = "ZRS"
enable_https_traffic_only = true
lifecycle {
prevent_destroy = true
}
tags = {
environment = var.environment
}
}# Create a Storage Container for the Core State File
resource "azurerm_storage_container" "core-container" {
depends_on = [azurerm_storage_account.state-sta]
name = "core-tfstate"
storage_account_name = azurerm_storage_account.state-sta.name
}Finally, we create the file az-remote-backend-output.tf file that will show the output:
output "terraform_state_resource_group_name" {
value = azurerm_resource_group.state-rg.name
}output "terraform_state_storage_account" {
value = azurerm_storage_account.state-sta.name
}output "terraform_state_storage_container_core" {
value = azurerm_storage_container.core-container.name
}5. Authenticating to Azure using a Service Principal (SPN) to use State Files in Remote Backend
If we want to use shared state files in a remote backend with SPN, we can configure Terraform using the following procedure:
We will create a configuration file with the credentials information. For this example, I called the file azurecreds.conf. This is the content of the file:
ARM_SUBSCRIPTION_ID="9c242362-6776-47d9-9db9-2aab2449703"
ARM_CLIENT_ID = "a47dd585-d5c1-4ffe-8ea2-91f0681c55bc"
ARM_CLIENT_SECRET="88f9776a-0e3h-4b9e-afcc-b4h3f17ad20h"
ARM_TENANT_ID="c7e7beb6-8e7c-41e7-bc41-37ggg3e33b665"then we create the file provider-main.tf and add the code to manage the Terraform and the Azure providers:
# Define Terraform provider
terraform {
required_version = ">= 0.12"
backend "azurerm" {
resource_group_name = "kopicloud-tfstate-rg"
storage_account_name = "kopicloudtfstate"
container_name = "core-tfstate"
key = "core.kopicloud.tfstate"
}
}# Configure the Azure provider
provider "azurerm" {
environment = "public"
}Finally, we initialize the Terraform configuration using this command:
terraform init -backend-config=azurecreds.confThen, we launch the stack as usual:
terraform apply -auto-approveAnd that’s all folks. If you liked this story, please show your support by 👏 this story. Thank you for reading!






