State Storage
Installing Terraform
Creating a new folder for this mini project
Initialize Terraform
terraform init
Create a main,tf file containing definition of storage account with storage account resource group
provider "azurerm" {
subscription_id = "<subscription_id>"
features {}
}
resource "azurerm_resource_group" "rg" {
name = "rg-terraform-state"
location = "East US"
}
resource "azurerm_storage_account" "storage_account" {
name = "tfstatestorageup"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
tags = {
environment = "Terraform State"
}
}
resource "azurerm_storage_container" "storage_container" {
name = "tfstate"
storage_account_name = azurerm_storage_account.storage_account.name
container_access_type = "private"
}
Create a sub folder for a new terraform module being whose the state will be stored to the storage account previously created.
Create a main.tf
# Resource group
provider "azurerm" {
subscription_id = "<subscription_id>"
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-rg-up"
location = "West Europe"
}
Create backend.tf (this will allow us to create update the state file remotely instead of locally)
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "tfstatestorageup"
container_name = "tfstate"
key = "terraform.tfstate"
}
}
Let’s look at the content of the state file in azure, in the storage account

https://portal.azure.com/#browse/Microsoft.Storage%2FStorageAccounts
Now, let’s make a add a new component in main.tf to the module service_plan
resource "azurerm_service_plan" "example" {
name = "example"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
os_type = "Linux"
sku_name = "P1v2"
}
And let’s now update the changes to the remote
terraform plan
terraform apply
Now, let’s check the state file in the storage account
At some point if we decide to delete manually one component, for e.g the service plan
we can use terraform refresh to adapt the state based on what is currently there
The `terraform refresh` command reads the current settings from all managed remote objects and updates the Terraform state to match.
https://stackoverflow.com/questions/42628660/what-does-terraform-refresh-really-do
Before refresh
{
"version": 4,
"terraform_version": "1.5.7",
"serial": 3,
"lineage": "2797f07b-bcf9-0097-2b05-8d1abd328b89",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "azurerm_resource_group",
"name": "example",
"provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "/subscriptions/<subscription_id>/resourceGroups/example-rg-up2",
"location": "westeurope",
"managed_by": "",
"name": "example-rg-up2",
"tags": null,
"timeouts": null
},
"sensitive_attributes": [],
"private": ""
}
]
},
{
"mode": "managed",
"type": "azurerm_service_plan",
"name": "example",
"provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"app_service_environment_id": "",
"id": "/subscriptions/<subscription_id>/resourceGroups/example-rg-up2/providers/Microsoft.Web/serverFarms/example",
"kind": "linux",
"location": "westeurope",
"maximum_elastic_worker_count": 1,
"name": "example",
"os_type": "Linux",
"per_site_scaling_enabled": false,
"premium_plan_auto_scale_enabled": false,
"reserved": true,
"resource_group_name": "example-rg-up2",
"sku_name": "P1v2",
"tags": null,
"timeouts": null,
"worker_count": 1,
"zone_balancing_enabled": false
},
"sensitive_attributes": [],
"private": "",
"dependencies": [
"azurerm_resource_group.example"
]
}
]
}
],
"check_results": null
}
After refresh
{
"version": 4,
"terraform_version": "1.5.7",
"serial": 4,
"lineage": "",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "azurerm_resource_group",
"name": "example",
"provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "/subscriptions/<subscription_id>/resourceGroups/example-rg-up2",
"location": "westeurope",
"managed_by": "",
"name": "example-rg-up2",
"tags": {},
"timeouts": null
},
"sensitive_attributes": [],
"private": ""
}
]
}
],
"check_results": null
}
Principle account
We recommend using either a Service Principal or Managed Service Identity when running Terraform non-interactively (such as when running Terraform in a CI server) – and authenticating using the Azure CLI when running Terraform locally.
Using the cli
az login
az account list
az account set --subscription="20000000-0000-0000-0000-000000000000"
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/20000000-0000-0000-0000-000000000000"
{
"appId": "00000000-0000-0000-0000-000000000000",
"displayName": "azure-cli-2017-06-05-10-41-15",
"name": "http://azure-cli-2017-06-05-10-41-15",
"password": "0000-0000-0000-0000-000000000000",
"tenant": "00000000-0000-0000-0000-000000000000"
}
These values map to the Terraform variables like so:
appId
is theclient_id
defined above.password
is theclient_secret
defined above.tenant
is thetenant_id
defined above.
Test out if the values are well working by using the azure cli
az login --service-principal -u CLIENT_ID -p CLIENT_SECRET --tenant TENANT_ID
{
"appId": "client_id", # client id
"displayName": "azure-cli-2025-02-27-09-50-08",
"password": "<client_secret>", # client secret
"tenant": "tenant_id" # tenant id
}

Early in my career, I specialized in the Python language. Python has been a constant in my professional life for over 10 years now. In 2018, I moved to London where I worked at companies of various sizes as a Python developer for five years. In parallel, I developed my activity as a Mentor, to which I now dedicate myself full-time.