DEV Community

Cover image for Azure Devops - Secure Reset of Terraform State
Dylan Morley
Dylan Morley

Posted on

Azure Devops - Secure Reset of Terraform State

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
Enter fullscreen mode Exit fullscreen mode

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 }}'"
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)