If you're using Terraform for Azure Infrastructure provisioning, you're likely using the Azure Storage Backend type for your state file.
When running a plan and apply, Terraform acquires a lock on the the state file to control concurrency (i.e. so that multiple deployments don't interfere with each other), and sometimes if a pipeline terminates abruptly you're left with a lock on the state file.
Next time you run the pipeline, you'll get something like
Error locking state: Error acquiring the state lock:
state blob is already locked
We've network restricted our storage accounts and are using a VM Scale Set associated with a subnet for our Azure Devops build pools. The subnet is allow listed on the storage account network restrictions, and the containers holding the state file are also RBAC restricted to the SPN associated with the Devops Service Connection. This means, only our Devops pipelines can interact with our Terraform state and therefore we need an azure pipeline to perform the unlock for us - so that we can authenticate and execute under the correct security context.
This is pretty simple, the only requirement here is to break the lease on the state file blob, which can be achieved with an AzureCLI task. By using this task type, authentication is performed via the specified Service Connection, which performs token management and allows access to the RBAC restricted container.
parameters:
- name : TerraformStateFile
displayName: Terraform State File (e.g. whatever.statefile.tfstate)
type: string
- name: ServiceConnectionName
default: YourServiceConnectionDefault
displayName: The name of the service connection that gives access to the storage account for the state file
type: string
- name: StorageAccountName
default: YourStorageDefault
displayName: The name of the storage account that holds the Terraform state files
type: string
trigger: none
steps:
- task: AzureCLI@2
displayName: "Break lease on terraform state"
name: BreakLease
inputs:
azureSubscription: ${{ parameters.ServiceConnectionName }}
scriptType: "pscore"
scriptLocation: "inlineScript"
inlineScript: "az storage blob lease break --container-name 'terraform' --blob-name '${{ parameters.TerraformStateFile }}' --account-name '${{ parameters.StorageAccountName }}'"
NB: The container name is hardcoded to 'terraform'
in this example, you could parameterise or set to whatever default works for you
Now, any team members can run the pipeline to reset state, without requiring any direct access to the storage account.
Top comments (0)