PowerShell, Office 365, Azure and automation
Unlock Terraform state on Azure storage

Unlock Terraform state on Azure storage

I’ve been in an awkward situation once, when I was provisioning Azure resources using Terraform via Azure DevOps pipeline. Pipeline stuck with the provisioning and I cancelled the apply step. The state file got locked. As it is stored on Azure Blob Storage in a dedicated container and only the Service Principal used to provision resources has access to that Azure Storage container I can’t easily go there and fix things manually myself. The situation is pretty standard, but the way to fix it requires a bit of tweaking around.

This is how the error looked like.

  Lock Info:
  ID:        77398269-7e09-f6e4-55de-e0477b41170e
  Path:      terraform-test-iac/project-test.tfstate
  Operation: OperationTypePlan
  Who:       root@adagent003-c
  Version:   1.1.1
  Created:   2022-01-25 05:16:07.1273806 +0000 UTC
  Info:      

How to get unblocked and unlock the state

Initially I thought that Terraform blocks a state file by writing something into the file itself. I was going to try to run Terraform locally from my machine, authenticate as a Service Account and release that lock with Terraform itself. It turned out that it is just a feature of a Azure Blob Storage that allows only 1 process to write to a file in a moment of time. That process should carefully close the session and release the lock. More details could be found here if you feel curious. I was more interested to unlock the state file and go ahead with my deployment.

I made a simple PowerShell script that will do the trick. You just need to go and collect all the required details. It is really 3 lines of code after.

## Required details
$azureAppId = "<ServicePrincipal_AppId>" # service principal that runs the pipeline AppID
$azureAppIdPassword = "<ServicePrincipal_Password>" # ServicePrincipal_Password
$subscriptionId = "<YourAzureSubscriptionId>" 
$tenantId = "<YourTenantId>"
$storageAccountName = "<YourStorageAccountName>" ## Where the Terraform state file stored
$storageBlobName = "<YourStorageBlobContainerName>" ## Where the Terraform state file stored
$resourceGroupName = "<ResourceGroupName>" ## Where the storage account resides
  

When you got all the details required in hand – connect to the Azure subscription with the Service Principal credentials. After the successfull connection, the last line is the action. Get the Storage Account in the Resource Group, get the Container name and release the lock.

# Make credentials object for authentication as a service principal
$azureAppCred = (New-Object System.Management.Automation.PSCredential $azureAppId, `
                ($azureAppIdPassword | ConvertTo-SecureString -asplaintext -force))

# Connect to Azure as a service principal
Connect-AzAccount -ServicePrincipal `
                  -SubscriptionId $subscriptionId `
                  -TenantId $tenantId `
                  -Credential $azureAppCred

# Break the lease from storage blob
$result = (Get-AzStorageAccount -Name $storageAccountName `
                                -ResourceGroupName $resourceGroupName | `
          Get-AzStorageBlob -Name $storageBlobName).ICloudBlob.BreakLease()

That should release the Terraform state file stored on Azure Storage Blob so you can get back to Azure resources deployment using a pipeline.

Thank you for reading!

You can find more about what can you do with PowerShell here

Leave a Reply

Your email address will not be published. Required fields are marked *