Skip to content

Latest commit

 

History

History
189 lines (135 loc) · 6.85 KB

File metadata and controls

189 lines (135 loc) · 6.85 KB

🗄️ Configure Terraform Remote State Storage

🎯 Learning Objectives

By the end of this lab, you'll be able to:

  • Understand why remote Terraform state is essential — for collaboration, consistency, and locking
  • Create an Azure Resource Group — as the logical container for your Terraform backend resources
  • Provision an Azure Storage Account and Blob Container — to store and lock the Terraform state file securely

⏱️ Estimated Time: ~10 minutes

✅ Prerequisites

Before starting, ensure you have:

  • Azure CLI installed and authenticated (az login)
  • Bash terminal (macOS/Linux or WSL on Windows)
  • Completed Lab 1.1 — Azure DevOps Setup
  • Active Azure subscription with Contributor or Owner permissions

🚀 Step-by-Step Implementation

Step 1: Customise the Script Variables

  1. 📂 Open the storage creation script

    Open scripts/create-terraform-storage.sh and update the following variables to match your environment:

    RESOURCE_GROUP_NAME="devops-journey-rg-apr2026"
    STORAGE_ACCOUNT_NAME="devopsjourneyapr2026"
    LOCATION="uksouth"
    CONTAINER_NAME="tfstate"

    ⚠️ Storage account names must be globally unique, 3–24 characters, lowercase alphanumeric only. Choose a name unique to you.


Step 2: Run the Script

  1. ▶️ Execute the script

    cd labs/1-Initial-Setup
    chmod +x scripts/create-terraform-storage.sh
    ./scripts/create-terraform-storage.sh

    ✅ Expected Output:

    Creating resource group: devops-journey-rg-apr2026
    {
      "id": "/subscriptions/.../resourceGroups/devops-journey-rg-apr2026",
      "location": "uksouth",
      "name": "devops-journey-rg-apr2026"
    }
    Creating storage account: devopsjourneyapr2026
    Storage account created successfully.
    Creating blob container: tfstate
    Blob container created successfully.
    
    ✅ Terraform backend resources created:
       Resource Group : devops-journey-rg-apr2026
       Storage Account: devopsjourneyapr2026
       Container      : tfstate
    

What the script does:

  • Creates an Azure Resource Group for all DevOps journey resources
  • Creates an Azure Storage Account with LRS redundancy and HTTPS-only enforcement
  • Creates a Blob Container named tfstate to store the Terraform state file
  • Enables blob versioning and soft-delete for state file protection

Step 3: Record Your Backend Values

Make note of the following — you will need them in the pipeline YAML configuration in Lab 2:

# Retrieve storage account key (needed for Terraform backend config)
az storage account keys list \
  --resource-group devops-journey-rg-apr2026 \
  --account-name devopsjourneyapr2026 \
  --query "[0].value" -o tsv

💡 In this lab we use the WIF service connection for authentication, so the storage key is only needed if you choose key-based backend auth. The pipeline uses the service connection's identity to access the storage account.


✅ Validation

Infrastructure checklist:

  • Resource group devops-journey-rg-apr2026 exists in Azure Portal
  • Storage account devopsjourneyapr2026 is present within the resource group
  • Blob container tfstate exists inside the storage account
# Validate resource group
az group show --name devops-journey-rg-apr2026 --query "{Name:name, Location:location, State:properties.provisioningState}" -o table

# Validate storage account
az storage account show \
  --name devopsjourneyapr2026 \
  --resource-group devops-journey-rg-apr2026 \
  --query "{Name:name, SKU:sku.name, HTTPS:enableHttpsTrafficOnly}" -o table

# Validate blob container
az storage container show \
  --name tfstate \
  --account-name devopsjourneyapr2026 \
  --auth-mode login \
  --query "{Name:name, PublicAccess:properties.publicAccess}" -o table

✅ Expected Output:

Name                       Location    State
-------------------------  ----------  ---------
devops-journey-rg-apr2026  uksouth     Succeeded

Name                    SKU         HTTPS
----------------------  ----------  -------
devopsjourneyapr2026    Standard_LRS  True

Name      PublicAccess
--------  ------------
tfstate   None

You can also verify visually in the Azure Portal:


🔧 Troubleshooting (click to expand)
# Problem: Storage account name already taken
# Solution: Choose a different, more unique name
# The name must be 3-24 lowercase alphanumeric characters and globally unique
STORAGE_ACCOUNT_NAME="devopsjourneyapr2026v2"

# Problem: Insufficient permissions to create resource group
# Solution: Ensure your account has Contributor or Owner on the subscription
az role assignment list --assignee "$(az account show --query user.name -o tsv)" \
  --query "[].roleDefinitionName" -o tsv

# Problem: "AuthorizationFailed" on container list
# Solution: Assign yourself Storage Blob Data Contributor on the storage account
az role assignment create \
  --assignee "$(az account show --query user.name -o tsv)" \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/devops-journey-rg-apr2026/providers/Microsoft.Storage/storageAccounts/devopsjourneyapr2026"

� Key Takeaways

  1. Remote state enables collaboration — multiple engineers can run terraform plan/apply against the same state without conflicts. Local state is per-developer and leads to drift.
  2. State locking prevents concurrent modifications — Azure Blob Storage supports lease-based locking so only one terraform apply runs at a time. Without locking, parallel runs can corrupt the state.
  3. Terraform loses track of resources without state — it would try to create all resources again, causing duplication or errors. Always back up state files using versioning and soft-delete.
  4. The blob container must not have public access — the state file may contain sensitive values including secrets, passwords, and keys in plaintext.

➡️ What's Next

Your Terraform remote state backend is ready. The storage account and container details will be used to configure the backend in your pipeline YAML in Lab 2.

← Back to Lab 1.1 | Continue to Lab 1.3 →


📚 Additional Resources