F Infrastructure as Code for Networking (Terraform + Cisco) - The Network DNA: Networking, Cloud, and Security Technology Blog

Infrastructure as Code for Networking (Terraform + Cisco)

HomeNetwork Automation › Infrastructure as Code for Networking

A practical guide for network engineers: how Terraform works, the Cisco provider ecosystem, real HCL config examples, state management, and a CI/CD pipeline for network changes

By Route XP  |  Published: March 2026  |  Network Automation, Cisco, Data Center

Terraform + Cisco — Declarative Network Automation with Infrastructure as Code

Terraform + Cisco — Declarative Network Automation with Infrastructure as Code

3,000+ Terraform Providers on Registry
80% Reduction in Config Errors with IaC
Faster Network Provisioning vs Manual
HCL HashiCorp Configuration Language

1. Why Network Engineers Need IaC

Network infrastructure has historically been configured the same way for decades — an engineer SSH's into a device, types commands, and hopes the running config matches what they intended. This approach doesn't scale, doesn't self-document, and has no rollback mechanism beyond a saved config file buried in someone's laptop.

Infrastructure as Code (IaC) applies software engineering discipline to network configuration: your network topology, VLANs, routing policies, and firewall rules are declared in version-controlled code files. Changes go through a review process. Every state transition is tracked. A misconfiguration is a git revert away from recovery.

For Cisco environments specifically — which often span ACI data centers, IOS-XE campus switches, SD-WAN fabrics, and Meraki cloud-managed sites — Terraform provides a single, consistent workflow to manage all of it declaratively, regardless of the underlying API.

📌 IaC vs Scripting: The Key Difference A Python script that configures VLANs is imperative — it tells the network what steps to execute. Terraform is declarative — you describe the desired end state and Terraform figures out the steps to get there. If a VLAN already exists, Terraform skips it. If a resource is removed from your code, Terraform deletes it. This idempotency is what makes IaC safe to re-run repeatedly.

2. How Terraform Works: Core Concepts

Terraform, built by HashiCorp (now part of IBM), uses a plugin-based architecture where providers translate HCL resource declarations into API calls for specific platforms. The workflow is always the same three commands, regardless of whether you're configuring AWS, a Cisco ACI fabric, or a Meraki dashboard.

The Terraform Workflow

# 1. Initialise — downloads providers and modules
terraform init

# 2. Plan — shows exactly what will change, nothing is applied yet
terraform plan -out=tfplan

# 3. Apply — executes the planned changes
terraform apply tfplan

The power is in terraform plan. Before touching a single device, Terraform prints a human-readable diff of every resource it intends to create, modify, or destroy. This is your change review step — it can be posted to a pull request, reviewed by a senior engineer, and approved before apply is ever run.

Core Building Blocks

Concept What It Is Network Example
Provider Plugin that translates HCL into platform API calls hashicorp/ciscoaci, ciscodevnet/iosxe
Resource A managed infrastructure object — created, updated, or destroyed by Terraform A VLAN, a BGP neighbour, an ACI EPG
Data Source Read-only query of existing infrastructure — not managed by Terraform Look up an existing ACI tenant ID to reference in a new EPG
Variable Parameterise your configuration for reuse across environments var.vlan_id, var.bgp_as_number
Module Reusable package of resources — your "network design patterns as code" A module that builds a full leaf-spine pair with standard policies
State Terraform's record of what it has deployed — the source of truth for drift detection terraform.tfstate — store remotely, never locally in production

3. The Cisco Provider Ecosystem

Cisco has invested significantly in Terraform provider coverage across its portfolio. Each provider communicates with its platform via a different underlying API — REST, NETCONF/RESTCONF, or a platform-specific SDK — but the HCL workflow is identical from the engineer's perspective.

Cisco Terraform Providers — Quick Reference
Provider Platform Underlying API Registry Namespace
ACI Cisco ACI / APIC APIC REST API hashicorp/aci
IOS-XE Catalyst, ISR, CSR1000v RESTCONF (RFC 8040) CiscoDevNet/iosxe
Meraki Meraki Dashboard Meraki Dashboard REST API CiscoDevNet/meraki
NX-OS Nexus switches NX-API REST / JSON-RPC CiscoDevNet/nxos
Intersight Cisco Intersight (UCS, HyperFlex) Intersight REST API CiscoDevNet/intersight

4. Real HCL Examples: ACI, IOS-XE, Meraki

Example 1 — Cisco ACI: Create a Tenant and VRF

This example provisions a new ACI tenant, a VRF, and a Bridge Domain — three of the most common day-one operations on an ACI fabric.

# providers.tf
terraform {
  required_providers {
    aci = {
      source  = "hashicorp/aci"
      version = "~> 2.9"
    }
  }
}

provider "aci" {
  username = var.apic_username
  password = var.apic_password
  url      = var.apic_url
  insecure = false
}

# main.tf — Tenant + VRF + Bridge Domain
resource "aci_tenant" "prod" {
  name = "PROD-Tenant"
  description = "Production workloads"
}

resource "aci_vrf" "prod_vrf" {
  tenant_dn = aci_tenant.prod.id
  name = "PROD-VRF"
  ip_data_plane_learning = "enabled"
}

resource "aci_bridge_domain" "web_bd" {
  tenant_dn = aci_tenant.prod.id
  name = "WEB-BD"
  relation_fv_rs_ctx = aci_vrf.prod_vrf.id
  arp_flood = "no"
  unicast_route = "yes"
}

Example 2 — IOS-XE: Configure a BGP Neighbour

The IOS-XE provider uses RESTCONF under the hood. From the engineer's perspective it is just HCL — no YANG models to hand-craft manually.

provider "iosxe" {
  host     = "https://192.0.2.1"
  username = var.ios_username
  password = var.ios_password
}

resource "iosxe_bgp" "core_bgp" {
  asn = "65001"
  router_id = "10.0.0.1"
}

resource "iosxe_bgp_neighbor" "peer1" {
  asn                = "65001"
  ip                 = "10.0.0.2"
  remote_as          = "65002"
  description        = "WAN-Peer-DC2"
  update_source_loopback = "0"
  ebgp_multihop      = 2
}

Example 3 — Meraki: Create a Network and Push an SSID

provider "meraki" {
  meraki_api_key = var.meraki_api_key
}

resource "meraki_networks" "branch_london" {
  organization_id = var.org_id
  name            = "Branch-London"
  product_types   = ["wireless", "switch", "appliance"]
  timezone        = "Europe/London"
}

resource "meraki_networks_wireless_ssids" "corp_wifi" {
  network_id              = meraki_networks.branch_london.network_id
  number                  = 0
  name                    = "Corp-WiFi"
  enabled                 = true
  auth_mode               = "8021x-radius"
  encryption_mode         = "wpa"
  wpa_encryption_mode     = "WPA2 Enterprise"
}
✅ Notice the Pattern Every example follows the same structure: declare a provider, declare resources that reference each other by ID, run terraform plan to preview, apply to execute. The learning curve is the HCL syntax and the specific resource attributes — not a new workflow per platform.

5. State Management and Remote Backends

Terraform's state file (terraform.tfstate) is a JSON record mapping every HCL resource to the real object it created on the network. It is how Terraform knows that aci_tenant.prod corresponds to tenant DN uni/tn-PROD-Tenant in your ACI fabric. Without state, every plan would appear to need a full re-creation of all resources.

🚫 Never Store State Locally in a Team Environment A local terraform.tfstate file on one engineer's machine means other team members cannot run Terraform safely — and if that file is lost, Terraform loses track of all managed resources. Always use a remote backend from day one.

Remote backends store state in a shared, versioned, locking-capable store. Common options for network teams:

Backend State Locking Best For
HCP Terraform (Terraform Cloud) ✅ Built-in Teams wanting managed runs, UI, and approval workflows
AWS S3 + DynamoDB ✅ DynamoDB lock AWS-native environments; cheap and widely understood
Azure Blob Storage ✅ Blob lease lock Azure-native environments
GitLab Managed Terraform State ✅ Built-in Teams already using GitLab CI/CD for network pipelines

State also enables drift detection. Running terraform plan against a stable environment shows any resource that has been changed out-of-band — for example, a VLAN deleted manually via the APIC GUI. This is one of the most operationally valuable capabilities of Terraform for network teams: it makes ad-hoc manual changes visible and revertible.

6. CI/CD Pipeline for Network Changes

The real transformation that IaC enables is treating network changes exactly like software deployments — with automated validation, peer review, and staged rollout. Here is a representative GitLab CI pipeline for a Cisco network change:

# .gitlab-ci.yml — Network IaC Pipeline
stages:
  - validate
  - plan
  - apply

validate:
  stage: validate
  script:
    - terraform init -backend=false
    - terraform validate
    - terraform fmt -check -recursive

plan:
  stage: plan
  script:
    - terraform init
    - terraform plan -out=tfplan
  artifacts:
    paths: [tfplan]
  # Plan output posts to MR as a comment for peer review

apply:
  stage: apply
  when: manual # Requires explicit approval — never auto-apply
  only: [main] # Only runs on merge to main branch
  script:
    - terraform apply tfplan

This pipeline enforces a critical discipline: no network change is applied without a plan artifact being reviewed and manually approved. The when: manual gate on the apply stage means a human must click "Run" in GitLab after reviewing the plan output posted to the merge request. This is the change management process — it's just automated.

7. Best Practices and Pitfalls

IaC for Networking — Do's and Don'ts
✅ Do 🚫 Don't
Store secrets (passwords, API keys) in a vault — pass to Terraform via environment variables or Vault provider, never in .tfvars committed to Git Commit secrets to any Git repository — even private ones. Rotate any key that has been accidentally committed immediately
Use terraform import to bring existing manually-created resources under Terraform management — don't start from a blank slate if the network already exists Run terraform apply directly in production without a reviewed plan. Always plan first; treat the plan as your change record
Separate state files per environment (dev/staging/prod) and per network domain (ACI, IOS-XE, Meraki) — using Terraform workspaces or separate state backends Manage all environments from a single state file — a mistake in one environment can affect others, and the blast radius of a terraform destroy is contained by state boundary
Use modules for repeatable patterns (e.g., a "standard branch network" module that creates VLANs, SVIs, and ACLs) — reduces copy-paste and enforces standards Put everything in a single monolithic main.tf — split resources into logical files (routing.tf, vlans.tf, security.tf) for readability
Pin provider versions with ~> 2.9 constraints — provider updates can change resource behaviour and break existing configurations Run terraform destroy on a production network without understanding the full dependency graph — Terraform will delete resources in dependency order, which may not match your expectation
⚠️ Start with Read-Only: Use Terraform Import Before Managing Existing Networks Before writing a single resource block for an existing network, run terraform plan against an empty configuration to understand what Terraform sees. Then use terraform import to bring existing resources into state one at a time. Attempting to re-create existing ACI objects by writing HCL without importing first will result in Terraform trying to create duplicate objects — which may fail loudly or, worse, create duplicates silently.

8. Frequently Asked Questions

Q: Do I need programming experience to use Terraform for networking?

No. HCL is a declarative configuration language, not a programming language — there are no loops, functions, or data structures to wrestle with for basic use cases. Most network engineers are productive with Terraform within a few days of learning the workflow. Familiarity with Git (commits, branches, pull requests) is more important than coding experience.

Q: What is the difference between Terraform and Ansible for network automation?

They solve different problems. Ansible is task-oriented and imperative — great for pushing configuration changes (run this playbook to update BGP timer values across 50 routers). Terraform is state-oriented and declarative — great for lifecycle management of network objects (create this ACI tenant with these EPGs; if I remove it from code, destroy it). Many teams use both: Terraform for provisioning the network infrastructure, Ansible for ongoing configuration management.

Q: Can Terraform roll back a network change?

Not automatically — Terraform is not a transaction system. To "roll back" you revert your HCL code to the previous version in Git and run terraform apply again. Terraform calculates the delta from the current state to the desired previous state and makes the necessary changes. This is why the plan review step is critical — it is your last line of defence before changes are applied.

Q: Is Terraform suitable for managing network devices that don't have a REST API?

For legacy IOS devices without RESTCONF, the netascode/iosxe provider can use NETCONF (SSH-based) on older IOS-XE versions. For truly legacy CLI-only devices, Ansible with the ios module via SSH is the better tool. Terraform works best with API-driven platforms — ACI, Meraki, and IOS-XE 16.12+ with RESTCONF enabled are all excellent targets.


Technical content based on HashiCorp Terraform documentation, Cisco DevNet provider documentation for ACI, IOS-XE, Meraki, and NX-OS, and GitLab CI/CD reference architecture. HCL examples are illustrative and should be validated in a non-production environment. All provider versions current as of March 2026.