Migrating Azure Storage Account Deployed Using Terraform- ‘Terraform Import Block’
As a DevOps Engineer, I understand how hectic it can be to perform a migration. For example, when a project requires migrating an Azure storage account provisioned using Terraform modules from one Resource Group (RG-1) to another (RG-2) with same name, several critical steps must be followed. We need to migrate this storage account to the new resource group with the same name and ensure that all dependent resources, initially deployed using Terraform modules, are also recreated in RG-2. Additionally, it is essential to follow DevOps best practices and ensure that the state files for both resource groups are up to date.
module "migration_poc_storage_account" {
source = "./module/storage_account"
for_each = toset(["pocsa"])
tags = {
"Environment" : "Dev",
}
location = "eastus2"
storage_account_name = "${lower("my${each.key}${local.location_abbr}")}devsa"
resource_group_name = "RG-1"
dfs_subnet = "mySubnet1"
lock_resource = false
}
Prerequisites:
- Ensure you have Terraform installed (>= v1.5.0) and configured with appropriate permissions to manage Azure resources (Backend Configuration)
- Login to azure using “az login” (Service Principle)
- Install Git, configure and clone the repository containing your Terraform configuration files.
Pre-Migration Considerations:
- Assess Current Environment: Understand the current setup of your storage account, including configurations, data, access controls, and dependencies.
- Expected Downtime: Plan for expected downtime during the migration process. Inform stakeholders and users about the maintenance window to minimize disruptions.
- Backup Data: Ensure that all data in the existing storage account is backed up before starting the migration. This can prevent data loss in case of any issues during the migration process.
- Check Dependencies: Identify all applications and services dependent on the storage account. Ensure these dependencies are properly managed and will function as expected post-migration.
- Network Configurations: Review and document existing network configurations, including private endpoint connections, firewall rules, and VNET integrations. These configurations will need to be re-established post-migration.
- Access Controls and Permissions: Document current access controls and permissions. Ensure that these settings are replicated in the new storage account setup.
- Update DNS and Connection Strings: Plan to update DNS settings, connection strings, and any other references to the storage account in your applications and services post-migration.
- Test Migration Plan: If possible, conduct a test migration in a staging environment to identify potential issues and ensure a smooth transition.
Introducing the import block feature from Terraform
Use the import
block to add existing infrastructure resources to Terraform's management. Unlike the terraform import
command, import
blocks are predictable, work well with CI/CD pipelines, and let you preview changes before updating the state.
Once imported, Terraform tracks the resource in your state file, allowing you to manage it like any other resource. This includes updating its attributes and destroying it as part of its lifecycle.
The import
block shows that Terraform imported the resource rather than creating it. You can remove import
blocks from your configuration after importing, or keep them as a record of the resource's origin.
This is what the block look like, Will Explain in detail
import {
to =
id =
}
The import block has the follwing arguments
to
— The Instance address this resource will have in your state file.id
— A string with the import ID of the resource. For example, you can provide a resource id of Azure resourceprovider
— An optional custom resource provider. This is useful when you’re using multiple providers. If you do not set theprovider
argument, Terraform attempts to import from the default provider.
Note: Import blocks are only available in Terraform v1.5.0 and later.
Let’s go through the steps like how can we achieve this.
Migration Steps:
- Terraform Refresh:
- Open a new Terminal
- Change the Directory where you terraform code lies on RG-1
- Run
terraform init
- Run
terraform workspace list
- Run
terraform workspace select <workspace_name>
in my case the workspace name isdev
- Run
terraform refresh
— to synchronize the Terraform state with the current state of your infrastructure.
2. Remove Remote Object Binding:
- Run
terraform state list
— to get the resources listed according to module depth order followed by alphabetical order. (Lists out all the resources that are tracked in the current state file.)
Here you can see all resources are linked toterraform state file
- Use
terraform state rm
to remove the binding to an existing remote object.terraform state rm <module.module_name>
- Run
terraform state rm module.migration_poc_storage_account
This command will remove all instances of the resources defined within the module named migration_poc_storage_account from the Terraform state.
Verification: Run “terraform state list” to get the resources listed and check the resources
3. Remove Private Endpoint Connections If Exists:
Manually remove private endpoint connections of existing storage accounts in the RG-1
using the Azure portal or Azure CLI.
- Navigate to Azure Portal, Select Storage Account Service, and select the storage account you want to migrate
- Scold down to Security + Networking Section on left side and select Networking
- Click on Private endpoints connections
- Tick on Connections name which will select all existing Private Endpoints
- Now click on Remove and Confirm Yes
4. Migrate Storage Account Resource:
Using the Azure portal, migrate the storage account resource from the RG-1 to the RG-2.
To migrate the storage account resource from the RG-1
to the RG-2
using the Azure portal, follow these steps:
- Navigate to Overview Page:- Go to the Azure portal and navigate to the overview page of the storage account resource you want to migrate.
- Initiate the Move:- Click on the
Move
dropdown menu. Select Destination Resource Group, Choose “Move to another resource group” option from the dropdown menu. Select the target resource group asRG-2
.
- Validation:- Click on “Next” and wait for the validation process to complete. Ensure that all validation checks pass successfully.
- Proceed with Migration:- Once the validation is successful, click on
next
to proceed.
- Confirmation:- Review the migration details. Tick the checkbox to confirm that you understand the implications of moving the resource. Click on “Move” to initiate the migration process.
- Monitor Migration: The storage account will start migrating from the
RG-1
to theRG-2
.Monitor the progress of the migration.You will receive a notification once the migration is completed successfully.
- Verification: Once it moved successfully go to
RG-2
and verify if the resource is exist
5. Update Terraform Configuration:
- Change working directory to where you terraform code lies for RG-2
- Run
terraform init
,terraform refresh
command - Update the Terraform configuration files (storage_account.tf) in the
RG-2
directory to include the migrated storage account. Cut the Module block fromRG-1
and Paste in storage_account.tf file ofRG-2
directory and make necessary changes to it like Resource Group name to RG-2 - Utilize the import block for the storage account resource in the
RG-2
Terraform files.
import {
to = module.migration_poc_storage_account["pocsalake"].azurerm_storage_account.blob
id = "<resource_id_of_migrates_storage_account_in_RG-2>"
}
# Dependency resources based on your module structure. Only need to import the resources that are migrated along with storage account
import {
to = module.migration_poc_storage_account["pocsalake"].azurerm_storage_management_policy.my_data_cycle
id = "<resource_id_of_migrated_storage_management_policy_in_RG-2>"
}
To get the ID of azurerm_storage_management_policy run az command
below
az storage account management-policy show --account-name "<storage_account_name>" --resource-group "<resource_group_name>"
import {
to = module.migration_poc_storage_account["pocsa"].azurerm_storage_account.blob
id = "<resource_id_of_migrates_storage_account_in_RG-2>"
}
import {
to = module.migration_poc_storage_account["pocsa"].azurerm_storage_management_policy.mars_data_cycle
id = "<resource_id_of_migrated_storage_management_policy_in_RG-2>"
}
module "migration_poc_storage_account" {
source = "./module/storage_account"
for_each = toset(["pocsa"])
tags = {
"Environment" : "Dev",
}
location = "eastus2"
storage_account_name = "${lower("my${each.key}${local.location_abbr}")}devsa"
resource_group_name = "RG-2"
dfs_subnet = "mySubnet2"
lock_resource = false
}
6. Verify Changes:
- Run
terraform state list
to list the resource binding here (RG-2).
- Run
terraform plan which
lets you preview the changes that Terraform plans to make to your infrastructure. Based on the module structure you will see the plan accordingly.
Here the 4 resources are that are adding by terraform are dependent resources from my storage account module
7. Apply Changes:
- Apply the changes to migrate the storage account resource by running
terraform apply
.
8. Verify State:
- After applying the changes, verify the storage account resource’s presence in the Terraform state file by running
terraform state list
- Verify Dependent resources are deployed successfully in RG-2