Managing Terraform Drift in Azure: A Step-by-Step Guide to Sync Resources
4 min read

Syncing Terraform with Azure: Handling Manual Changes to Resources
Terraform is a powerful Infrastructure-as-Code (IaC) tool that allows you to manage your cloud infrastructure declaratively. However, scenarios can arise where resources created with Terraform are manually modified in the Azure Portal or via other means. This can lead to a mismatch, or "drift," between Terraform’s state and the actual infrastructure.
In this blog, we’ll explore how to handle such situations effectively. Let’s consider a scenario where a Virtual Machine (VM) and a Network Security Group (NSG) were created using Terraform but were later manually modified in Azure. For example, additional rules were added to the NSG.
Infrastructure Deployed:
I deployed Linux VM and associated nsg to the VM-Nic.
resource "azurerm_virtual_network" "vnet-clouddevinsights" {
name = var.virtual_network_name
address_space = var.address_space
location = var.resource_group_location
resource_group_name = var.resource_group_name
}
resource "azurerm_subnet" "vnet-clouddevinsights-subnet" {
name = var.subnet_name
resource_group_name = azurerm_resource_group.clouddevinsights.name
virtual_network_name = azurerm_virtual_network.vnet-clouddevinsights.name
address_prefixes = var.subnet_address_prefix
}
resource "azurerm_network_security_group" "nsg-clouddevinsights-nsg" {
name = var.network_security_group_name
location = var.resource_group_location
resource_group_name = azurerm_resource_group.clouddevinsights.name
security_rule {
name = "Allow-SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "Allow-HTTP"
priority = 1002
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "Allow-HTTPS"
priority = 1003
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_network_interface" "vm-nic" {
name = var.vm-nic-name
location = azurerm_resource_group.clouddevinsights.location
resource_group_name = azurerm_resource_group.clouddevinsights.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.vnet-clouddevinsights-subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_network_interface_security_group_association" "nsg-association" {
network_interface_id = azurerm_network_interface.vm-nic.id
network_security_group_id = azurerm_network_security_group.nsg-clouddevinsights-nsg.id
}
resource "azurerm_linux_virtual_machine" "linux-vm" {
name = var.vm-name
resource_group_name = azurerm_resource_group.clouddevinsights.name
location = var.resource_group_location
size = "Standard_B1s"
admin_username = "adminuser"
admin_password = "Password1234!"
disable_password_authentication = "false"
network_interface_ids = [
azurerm_network_interface.vm-nic.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
}
Make Changes in Azure:
I will add a NSG rule manually using Azure Portal. I will allow all inbound traffic from internet.
Steps to Sync Terraform with Azure
Step 1: Update Terraform’s State File
Terraform’s state file does not automatically reflect changes made directly in Azure. To synchronize the state file with the actual infrastructure, use the following command:
terraform refresh
This command fetches the latest state of the resources from Azure and updates the local state file. For example, if you added new rules to the NSG or changed the VM size, these changes will now be reflected in Terraform’s state.
Step 2: Detect Drift Using terraform plan
After refreshing the state, run the terraform plan
command to identify any differences between the actual resources in Azure and the desired configuration defined in your .tf
files:
terraform plan
Terraform will analyze the current state and the configuration files to detect any drift. It will display a plan of actions needed to bring the infrastructure back in line with the desired state. For example, it might show that the VM size or NSG rules differ from the configuration. Please see the image below to see the drift.
Step 3: Apply Changes to Sync Resources
If drift is detected, you can apply the necessary changes to align the resources with your Terraform configuration. Use the following command:
terraform apply
Terraform will prompt you to confirm the changes. Once confirmed, it will update the Azure resources to match the desired configuration. For example, it might:
- Remove any manually added rules in the NSG that are not in the Terraform configuration.
Special Case: Both Terraform and Azure Modify Resources
If both Terraform and Azure have modified the same resources, it’s crucial to ensure that Terraform’s state file is up-to-date before applying changes. Here’s why:
Terraform Updates the State File: When Terraform applies changes, it updates the state file to reflect the new state of the resources.
Manual Changes in Azure: If resources are manually modified after Terraform’s state file has been updated, Terraform may overwrite those changes during the next apply operation.
To avoid unintentional overwrites:
Always run
terraform refresh
andterraform plan
before applying changes.Communicate with your team to establish clear guidelines for managing resources.
Key Takeaways
Avoid Manual Changes: The best practice is to avoid manual changes to resources managed by Terraform. This ensures consistency and reduces the risk of drift.
Refresh State Regularly: Use
terraform refresh
to keep the state file in sync with the actual infrastructure.Detect and Resolve Drift: Use
terraform plan
to detect drift andterraform apply
to resolve it.Establish Governance: Set clear policies to manage resources and avoid conflicts between manual changes and Terraform.
By following these steps, you can ensure that your infrastructure remains consistent, predictable, and aligned with your Terraform configurations. Handling drift effectively is a critical skill for any cloud professional, and it ensures that your IaC workflows remain robust and reliable.