Skip to content

Managing Configuration Drift

Managing SD-WAN Configuration Drift with Terraform: Detection and Remediation Strategies

Section titled “Managing SD-WAN Configuration Drift with Terraform: Detection and Remediation Strategies”

Configuration drift occurs when the actual state of network infrastructure deviates from the desired state defined in your Network as Code (NaC) repository. This comprehensive guide demonstrates how to detect, understand, and remediate configuration drift in Cisco SD-WAN environments using Terraform, covering three common drift scenarios with practical remediation strategies.

This article addresses the common issue of configuration drift in Cisco SD-WAN environments when using a Network-as-Code solution based on Terraform. Configuration drift occurs when the actual state of the network deviates—more precisely, when the controller state diverges—from the desired state defined in your Git repository and stored in your Terraform state. This can lead to inconsistencies, unexpected behavior, and challenges in managing your SD-WAN infrastructure.

Key Takeaways:

  • Learn to identify different types of configuration drift in SD-WAN
  • Master Terraform import workflows for complex drift scenarios
  • Implement best practices for maintaining configuration consistency
  • Understand the relationship between Terraform state and SD-WAN controller objects

Configuration drift in SD-WAN environments typically occurs through:

  • Manual UI changes on the SD-WAN controller
  • Direct API modifications outside of Terraform
  • Out-of-band automation tools making changes
  • Template inheritance causing unexpected configurations
Drift TypeDescriptionRemediation Complexity
Property DriftExisting objects with modified propertiesLow
Deletion DriftResources removed from controllerLow
Recreation DriftResources deleted and recreated with same nameHigh
Cross-Module DriftChanges affecting multiple Terraform modulesVery High

The demonstration environment consists of a simple CML SD-WAN setup with 3 sites connected via different transport methods:

SDWAN Topology

Environment Details:

  • Sites: 3 locations (HQ, Branch, Remote)
  • Devices: C8000V routers at each site
  • Transport: Combination of MPLS and Internet links
  • Templates: Centralized device and feature templates
  • Policies: Centralized and localized policies
  • Terraform >= 1.0 installed
  • Cisco SD-WAN Terraform provider configured
  • Access to SD-WAN Manager controller
  • Git repository with terraform configurations
  • Network-as-Code (NaC) data model files
nac-sdwan-example/
├── data/
│ ├── centralized_policies.nac.yaml
│ ├── edge_device_templates.nac.yaml
│ ├── edge_feature_templates.nac.yaml
│ ├── localized_policies.nac.yaml
│ ├── policy_objects.nac.yaml
│ └── sites.nac.yaml
├── terraform.tfstate
└── main.tf

Deploy your Day 0 SD-WAN configuration:

Terminal window
# Initialize and apply base configuration
terraform init
terraform plan # Review planned changes
terraform apply # Deploy 150+ resources
Terminal window
# Expected output (condensed)
Plan: 150 to add, 0 to change, 0 to destroy.
...
Apply complete! Resources: 150 added, 0 changed, 0 destroyed.

So I have my Day 0 configuration for my devices, sites, and policies applied and in sync with the SD-WAN controller.

Day 0 SDWAN Devices InventoryDay 0 SDWAN Device and Feature Templates

Before we create drift, let’s also analyze the Terraform state to see how my objects, let’s say templates, are represented in the state.

I will use the FT-CEDGE-AAA-02 AAA template as an example to analyze in the following steps.

If you open your terraform.tfstate file and look for the FT-CEDGE-AAA-02 template, you can see its representation below in JSON format:

Terraform State File for FT-CEDGE-AAA-02 Template

The ID 1ca42e37-42ef-4baf-ae93-35d9c38f6364 shown above is exactly the same ID you can see in the SD-WAN controller UI for the same template:

SDWAN Controller UI for FT-CEDGE-AAA-02 Template

This ID is assigned by the SD-WAN controller when the object is created, and this is how Terraform keeps track of the objects it manages, linking them with the names we define in our configuration and data model files.


This scenario covers the most common drift type: manual changes to existing resource properties through the SD-WAN controller UI.

We’ll modify the FT-CEDGE-AAA-02 AAA feature template by:

  • Changing name from FT-CEDGE-AAA-02 to FT-CEDGE-AAA-02-DRIFTED
  • Updating description to This is a drifted AAA template

Before creating drift, let’s examine how Terraform tracks this resource:

{
"mode": "managed",
"type": "sdwan_cedge_aaa_feature_template",
"name": "cedge_aaa_feature_template",
"instances": [
{
"attributes": {
"id": "1ca42e37-42ef-4baf-ae93-35d9c38f6364",
"name": "FT-CEDGE-AAA-02",
"description": "TACACS, Local auth"
}
}
]
}

🔍 Key Insight: The id field links Terraform state to the actual SD-WAN controller object.

  1. Navigate to Configuration → Templates → Feature Templates
  2. Edit FT-CEDGE-AAA-02 template
  3. Change name to FT-CEDGE-AAA-02-DRIFTED
  4. Update description to This is a drifted AAA template
  5. Save changes

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Drifted

Terminal window
terraform plan
Terminal window
# Terraform detects the drift
Terraform will perform the following actions:
# module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"] will be updated in-place
~ resource "sdwan_cedge_aaa_feature_template" "cedge_aaa_feature_template" {
~ description = "This is a drifted AAA template" -> "TACACS, Local auth"
~ name = "FT-CEDGE-AAA-02-DRIFTED" -> "FT-CEDGE-AAA-02"
# (other attributes unchanged)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Terminal window
terraform apply
Terminal window
# Remediation output
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Modifying... [id=1ca42e37-42ef-4baf-ae93-35d9c38f6364]
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Modifications complete after 0s
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

If we go back to the SD-WAN UI, we can see the name is back to FT-CEDGE-AAA-02 and the description is back to TACACS, Local auth.

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Remediated

Also, if we open and view it again, we’ll see it’s back to the original state.

SDWAN Controller UI for FT-CEDGE-AAA-02 Template View Remediated

Result: Configuration restored to desired state as defined in YAML data model.


This scenario demonstrates drift detection and remediation when resources are completely removed from the SD-WAN controller.

  1. Navigate to SD-WAN controller UI
  2. Delete the FT-CEDGE-AAA-02 feature template
  3. Confirm deletion

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Deleted

Confirm Deletion of FT-CEDGE-AAA-02 Template

Terminal window
terraform plan
Terminal window
# Terraform plans to recreate the deleted resource
Terraform will perform the following actions:
# module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"] will be created
+ resource "sdwan_cedge_aaa_feature_template" "cedge_aaa_feature_template" {
+ description = "TACACS, Local auth"
+ name = "FT-CEDGE-AAA-02"
+ id = (known after apply)
# ... full configuration details
}
Plan: 1 to add, 0 to change, 0 to destroy.
Terminal window
terraform apply
Terminal window
# Recreation output
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Creating...
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Creation complete after 0s [id=411e1506-910c-4c2e-8fdb-acd554b40b64]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Now if we go back to the SD-WAN controller UI, we can see that the FT-CEDGE-AAA-02 template is back.

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Recreated

SDWAN Controller UI for FT-CEDGE-AAA-02 Template View Recreated

If we check again in our Terraform state file, we can see the new ID for the FT-CEDGE-AAA-02 template.

{
"mode": "managed",
"type": "sdwan_cedge_aaa_feature_template",
"name": "cedge_aaa_feature_template",
"instances": [
{
"attributes": {
"id": "411e1506-910c-4c2e-8fdb-acd554b40b64",
"name": "FT-CEDGE-AAA-02",
"description": "TACACS, Local auth"
}
}
]
}

Result: Template successfully recreated with identical configuration.


Drift Scenario 3: Recreation with Same Name

Section titled “Drift Scenario 3: Recreation with Same Name”

This is the most complex scenario: a resource is deleted and manually recreated with the same name but different configuration.

  1. Delete FT-CEDGE-AAA-02 from SD-WAN controller
  2. Create new template with same name but minimal configuration:
    • Device type: C8000V only
    • Server groups: local only (no TACACS)
    • No additional users configured

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Deleted Again

Confirm Deletion of FT-CEDGE-AAA-02 Template Again

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Created Again

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Created Again

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Created Again

SDWAN Controller UI for FT-CEDGE-AAA-02 Template View Created Again

Terminal window
terraform apply
Terminal window
# Error: Template name conflict
Error: Client Error
Failed to create template (POST), got error: HTTP Request failed:
StatusCode 400, {"error":{"message":"Template with name 'FT-CEDGE-AAA-02' already exists"}}

Problem: Terraform cannot create a new resource with the same name, nor can it update the existing one because the IDs don’t match.

From the SD-WAN controller UI, note the new template ID: f7155708-baa6-4548-a478-ca03a4b44a29

SDWAN Controller UI for FT-CEDGE-AAA-02 Template View Created Again Details

Terminal window
# Import syntax for module resources
terraform import 'module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]' "f7155708-baa6-4548-a478-ca03a4b44a29"
Terminal window
# Import output
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Import prepared!
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Refreshing state... [id=f7155708-baa6-4548-a478-ca03a4b44a29]
Import successful!

Let’s look now in our Terraform state file—we can see the new ID for the FT-CEDGE-AAA-02 template.

{
"mode": "managed",
"type": "sdwan_cedge_aaa_feature_template",
"name": "cedge_aaa_feature_template",
"instances": [
{
"attributes": {
"id": "f7155708-baa6-4548-a478-ca03a4b44a29",
"name": "FT-CEDGE-AAA-02",
"description": "Local auth"
}
}
]
}
Terminal window
terraform plan
Terminal window
# Terraform now plans to update the imported resource
# module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"] will be updated in-place
~ resource "sdwan_cedge_aaa_feature_template" "cedge_aaa_feature_template" {
~ device_types = [
+ "vedge-C8200-1N-4T",
+ "vedge-C8200L-1N-4T",
# ... additional device types
]
~ server_groups_priority_order = "local" -> "TACACS-GROUP1,TACACS-GROUP2,local"
+ tacacs_server_groups = [
# ... TACACS configuration
]
+ users = [
# ... user configuration
]
}
Plan: 0 to add, 1 to change, 0 to destroy.
Terminal window
terraform apply
Terminal window
# Update output
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Modifying... [id=f7155708-baa6-4548-a478-ca03a4b44a29]
module.sdwan.sdwan_cedge_aaa_feature_template.cedge_aaa_feature_template["FT-CEDGE-AAA-02"]: Modifications complete after 0s
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Let’s look now in the SD-WAN controller UI, we can see that the FT-CEDGE-AAA-02 template is updated to match the desired state as defined in the Terraform configuration files.

SDWAN template Updated After Import

SDWAN Controller UI for FT-CEDGE-AAA-02 Template Updated After Import

{
"mode": "managed",
"type": "sdwan_cedge_aaa_feature_template",
"name": "cedge_aaa_feature_template",
"instances": [
{
"attributes": {
"id": "f7155708-baa6-4548-a478-ca03a4b44a29",
"name": "FT-CEDGE-AAA-02",
"description": "TACACS, Local auth"
}
}
]
}

Result: Resource successfully aligned with desired state configuration.

You can find how to import data in Terraform using the provider documentation here.

For modules, use the documentation here

For different SD-WAN resources, use these import patterns:

Terminal window
# Feature Templates
terraform import 'module.sdwan.sdwan_cedge_<template_name>_feature_template.template_name["KEY"]' "RESOURCE_ID"
# Device Templates
terraform import 'module.sdwan.sdwan_feature_device_template.device_template["KEY"]' "RESOURCE_ID"
# Policy Objects
terraform import 'module.sdwan.sdwan_<policy_object>_policy_object.policy_object["KEY"]' "RESOURCE_ID"
# Centralized Policies
terraform import 'module.sdwan.sdwan_centralized_policy.policy["KEY"]' "RESOURCE_ID"

Sometimes manual changes are unavoidable. To mitigate drift risks, integrate Terraform plans into your CI/CD pipelines to automatically detect and alert on configuration changes. Example GitHub Actions workflow:

.github/workflows/drift-detection.yml
name: SD-WAN Drift Detection
on:
schedule:
- cron: '0 8 * * MON-FRI' # Daily weekday checks
jobs:
drift-detection:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Plan
run: terraform plan -detailed-exitcode
# Exit code 2 indicates changes detected
  • Limit UI access to the SD-WAN controller for day-to-day operations
  • Implement RBAC with read-only access for most users
  • Use break-glass procedures for emergency manual changes
  • Audit all changes through controller logs
Diagram
  • Use a version control system such as Git to store the current configuration before making changes
  • Review Terraform plan output thoroughly
  • Check for resource dependencies that might be affected
  • Validate in a staging environment if possible
  • Schedule a maintenance window for production changes

The last example shows how Terraform can detect and remediate drift in the SD-WAN controller configuration. In all the examples we performed, we were able to remediate the drift and bring the configuration back to the desired state as defined in the data model YAML file and Terraform state file. It’s also important that all the changes were part of the same Terraform module that handles implementation of the AAA feature template. If a change is made outside the module scope and across multiple modules, remediation becomes more complex and requires additional planning and testing before production implementation.

Let’s say if we analyze the Terraform module for the device template, we can see that we have multiple resources which are part of the module and span multiple modules, increasing complexity. Terraform Network-as-Code Cisco SD-WAN Module

Terraform Module for Device Template

If we change more than one resource across multiple modules, complexity increases and we need to plan and test the changes before bringing the configuration back to the desired state.

In this blog post, we have seen how to use Terraform to manage and automate the configuration of the Cisco SD-WAN controller. We have defined the desired state of the SD-WAN controller using Terraform configuration files and applied those configurations to the controller. We have also seen how to detect and remediate drift in the SD-WAN controller configuration using Terraform. We have further illustrated how this can easily get out of control depending on the type of change performed and how to reconcile the configuration back to the desired state.

For operational purposes, it is very important to have a good understanding of the configuration and the impact of the changes you make. It is also critical to have a thorough testing and validation process before applying changes in a production environment, which—if you are using a Network-as-Code approach—should be part of your existing CI/CD pipeline.

None of the changes demonstrated in this blog post were part of a CI/CD pipeline; they were done manually for demonstration purposes. In a real-world scenario, you should have a robust CI/CD pipeline in place to validate and test changes before applying them in production and to minimize or avoid any UI-based changes that could lead to configuration drift.

Through our exploration of three drift scenarios, we’ve learned that:

  1. Property modifications are easily detected and remediated with standard Terraform workflows
  2. Resource deletions require recreation, resulting in new resource IDs
  3. Same-name recreations require the Terraform import workflow for resolution
  4. Complex multi-module drifts need careful planning and sequential remediation
PracticeBenefitImplementation
Automated drift detectionEarly problem identificationCI/CD pipeline integration
Restricted UI accessDrift preventionRBAC implementation
Regular state backupsRecovery capabilityAutomated backup scripts
Import proceduresComplex drift resolutionDocumented workflows
Change managementControlled modificationsProcess enforcement

For production SD-WAN environments:

  1. Implement daily drift detection through automated Terraform plan executions
  2. Establish clear escalation procedures for different drift severity levels
  3. Maintain comprehensive documentation of import procedures and resource dependencies
  4. Regular team training on drift detection and remediation workflows
  5. Develop rollback procedures for failed remediation attempts