Modify or edit remote Terraform state file in Azure

There may be a time where you are required to modify or edit remote Terraform state in Azure – in this blog I will show how you can achieve this!

Why may I need to edit or modify?

There can be various reasons; usually it may be required to perform a Terraform import of a current resource already deployed or potentially deleting a resource from remote state!

Lets begin!

Folder structure

Terraform-edit-remote-state
    └── terraform
       └── main.tf
    └── scripts
       └── terraform-init.sh

I will start off by wanting to create a resource group & storage account (these have been pre-created & remote state stored within a storage account blob)

main.tf

provider "azurerm" {
  features {}
}

terraform {
    backend "azurerm" {
    }
}

# Create Resource Group
resource "azurerm_resource_group" "tamops-rg" {
  name     = "tamops-rg"
  location = "UK South"
}

# Create Storage Account
resource "azurerm_storage_account" "tamops-sa" {
  name                = "tamopssa"
  resource_group_name = azurerm_resource_group.tamops-rg.name

  location                 = azurerm_resource_group.tamops-rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

}

Checking in Azure Portal we can these resources have been created

Notice there is another 2 additional storage accounts? These were created manually – we want to add these two storage accounts via Terraform.

Before we do that, lets initialise to the remote state file. With folder structure mentioned above, ensure you are in the terraform folder location. Run terraform-init.sh from the scripts folder. (Change values to your specific remote state file)

Terraform-edit-remote-state/terraform$ terraform init -backend-config storage_account_name=tfstatedevops -backend-config container_name=editterraformstate -backend-config resource_group_name=tamopstfstates -backend-config key=editstate.tfstate        

Initializing the backend...

Successfully configured the backend "azurerm"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding latest version of hashicorp/azurerm...
- Installing hashicorp/azurerm v2.59.0...
- Installed hashicorp/azurerm v2.59.0 (self-signed, key ID 34365D9472D7468F)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

Now that we have initialised to the remote state file, we can view what is currently in remote state using terraform state list

Terraform-edit-remote-state/terraform$ terraform state list
azurerm_resource_group.tamops-rg
azurerm_storage_account.tamops-sa

Additional information on commands that can be done within terraform state

Usage: terraform state <subcommand> [options] [args]

  This command has subcommands for advanced state management.

  These subcommands can be used to slice and dice the Terraform state.
  This is sometimes necessary in advanced cases. For your safety, all
  state management commands that modify the state create a timestamped
  backup of the state prior to making modifications.

  The structure and output of the commands is specifically tailored to work
  well with the common Unix utilities such as grep, awk, etc. We recommend
  using those tools to perform more advanced state tasks.

Subcommands:
    list                List resources in the state
    mv                  Move an item in the state
    pull                Pull current state and output to stdout
    push                Update remote state from a local state file
    replace-provider    Replace provider in the state
    rm                  Remove instances from the state
    show                Show a resource in the state

Adding the two additional storage accounts into main.tf

# Create Storage Account2
resource "azurerm_storage_account" "tamops-sa2" {
  name                = "tamopssa2"
  resource_group_name = azurerm_resource_group.tamops-rg.name

  location                 = azurerm_resource_group.tamops-rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

}

# Create Storage Account3
resource "azurerm_storage_account" "tamops-sa3" {
  name                = "tamopssa3"
  resource_group_name = azurerm_resource_group.tamops-rg.name

  location                 = azurerm_resource_group.tamops-rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

}

Attempting to perform a terraform apply does perform a successful plan but once you attempt to apply – you will receive two errors similar to the below

Error: A resource with the ID "/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa2" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_storage_account" for more information.

  on main.tf line 28, in resource "azurerm_storage_account" "tamops-sa2":
  28: resource "azurerm_storage_account" "tamops-sa2" {



Error: A resource with the ID "/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa3" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_storage_account" for more information.

  on main.tf line 39, in resource "azurerm_storage_account" "tamops-sa3":
  39: resource "azurerm_storage_account" "tamops-sa3" {

That is because the resource is already deployed, we will now perform a terraform import of each resource into the remote state file

The below is importing azurerm_storage_account.tamops-sa2, I have also done the same for azurerm_storage_account.tamops-sa3 but have not included in this example

Terraform-edit-remote-state/terraform$ terraform import azurerm_storage_account.tamops-sa2 /subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa2
Acquiring state lock. This may take a few moments...
azurerm_storage_account.tamops-sa2: Importing from ID "/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa2"...
azurerm_storage_account.tamops-sa2: Import prepared!
  Prepared azurerm_storage_account for import
azurerm_storage_account.tamops-sa2: Refreshing state... [id=/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa2]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Releasing state lock. This may take a few moments...

As these two storage accounts are now imported into Terraform state, if we attempt a terraform apply now – there will be no changes needed to be applied

thomasthorntoncloud-azure-devops/Terraform-edit-remote-state/terraform$ terraform apply
Acquiring state lock. This may take a few moments...
azurerm_resource_group.tamops-rg: Refreshing state... [id=/subscriptions/27f048cd-d37e-4655-8fbe-2e41b14d7327/resourceGroups/tamops-rg]
azurerm_storage_account.tamops-sa: Refreshing state... [id=/subscriptions/2XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa]
azurerm_storage_account.tamops-sa3: Refreshing state... [id=/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa3]
azurerm_storage_account.tamops-sa2: Refreshing state... [id=/subscriptions/XXXXXXXXXXXXX/resourceGroups/tamops-rg/providers/Microsoft.Storage/storageAccounts/tamopssa2]

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

terraform state list will show the two new resources have been added successfully also

Terraform-edit-remote-state/terraform$ terraform state list
azurerm_resource_group.tamops-rg
azurerm_storage_account.tamops-sa
azurerm_storage_account.tamops-sa2
azurerm_storage_account.tamops-sa3

Additional Terraform state commands

Wanting to change the name of a resource reference within your Terraform state file? No problem!

I am going to change tamops-sa2 to tamops-sa-newname

resource "azurerm_storage_account" "tamops-sa-newname" {
  name                = "tamopssa3"
  resource_group_name = azurerm_resource_group.tamops-rg.name

  location                 = azurerm_resource_group.tamops-rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

}

This can be done using terraform state mv

Terraform-edit-remote-state/terraform$ terraform state mv azurerm_storage_account.tamops-sa3 azurerm_storage_account.tamops-newname
Acquiring state lock. This may take a few moments...
Move "azurerm_storage_account.tamops-sa3" to "azurerm_storage_account.tamops-newname"
Successfully moved 1 object(s).

Terraform-edit-remote-state/terraform$ terraform state list
azurerm_resource_group.tamops-rg
azurerm_storage_account.tamops-newname
azurerm_storage_account.tamops-sa
azurerm_storage_account.tamops-sa2

Want to remove a resource from Terraform state file but not wanting to have the actual Azure resource deleted? This can be done using terraform rm

I will remove tamops-sa-newname from terraform state file

Terraform-edit-remote-state/terraform$ terraform state rm azurerm_storage_account.tamops-newname
Acquiring state lock. This may take a few moments...
Removed azurerm_storage_account.tamops-newname
Successfully removed 1 resource instance(s).
Releasing state lock. This may take a few moments...

Terraform-edit-remote-state/terraform$ terraform state list
azurerm_resource_group.tamops-rg
azurerm_storage_account.tamops-sa
azurerm_storage_account.tamops-sa2

Awesome! Hopefully you have gained an insight into modifying or editing remote Terraform state in Azure – thanks for reading!

GitHub Repository

4 comments

    1. I would not recommend doing this via DevOps pipeline , I much prefer to have the cli locally and edit/modify what I require. It is something you probably should not be needing to do too often.

      If you did want to do via DevOps pipeline – the CLI commands work fine within pipeline

Leave a Reply