TerraformNetwork AutomationIaC

Terraform for Network Automation: Patterns That Actually Work in Production

28 August 2026 · Sphinx-Digital

Terraform is everywhere for cloud resources. It is far less common for network gear, which is a shame: the state machine model fits declarative network configuration surprisingly well. Here are the patterns that survive contact with a real production network.

Why Terraform for Networks?

The usual argument for Ansible in networking is flexibility — you can conditionally push config, handle vendor quirks, and react to state. The argument for Terraform is idempotency with drift detection: terraform plan tells you exactly what will change before you change it, and the state file tracks divergence between declared and actual config.

Both tools have their place. The pattern that works at scale is: Terraform for persistent, long-lived network state (VLANs, BGP peers, firewall policies, DNS records) and Ansible for operational tasks (rolling upgrades, log collection, one-time remediations).

Remote State First

The single biggest mistake in Terraform network projects is local state. State must live in a shared backend from day one. For a network team:

terraform {
  backend "s3" {
    bucket         = "mycompany-tf-state"
    key            = "network/prod/terraform.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "tf-state-lock"
    encrypt        = true
  }
}

DynamoDB locking prevents concurrent applies. If two engineers run terraform apply simultaneously without a lock, you get state corruption. This is not theoretical — it happens on the first week of a team adopting Terraform.

Module Structure for Network Infrastructure

A flat Terraform project that manages an entire network is unmanageable by month three. The structure that scales:

modules/
  network-segment/    # VLANs, prefixes, routing instances
  firewall-policy/    # Rule sets, NAT, VIP
  bgp-peer/           # Peer config, prefix filters
  dns-zone/           # Records, TTL management
environments/
  prod/
  staging/
  lab/

Each environment consumes the modules with environment-specific variables. The modules handle the logic; the environments handle the values.

The NetBox Provider Pattern

The netbox Terraform provider (maintained by the community, ~2k downloads/week) lets you declare network objects in NetBox from Terraform, then consume them in your infrastructure config:

# Declare a prefix in NetBox
resource "netbox_prefix" "dmz_segment" {
  prefix      = "10.200.1.0/24"
  status      = "active"
  description = "DMZ — web tier"
  vrf_id      = data.netbox_vrf.prod.id
  site_id     = data.netbox_site.paris.id
}

# Use that prefix in Palo Alto policy
resource "panos_security_policy" "allow_dmz_outbound" {
  source_zones      = ["dmz"]
  destination_zones = ["internet"]
  source_addresses  = [netbox_prefix.dmz_segment.prefix]
  # ...
}

This creates a documented chain: NetBox is the SoT, Terraform is the executor, and the firewall state is always derivable from the Terraform state.

Handling Stateful Network Devices

Network devices are not stateless cloud resources. A BGP session has its own state that Terraform cannot directly observe. The pattern for this is lifecycle + ignore_changes:

resource "junos_bgp_neighbor" "upstream" {
  ip             = "203.0.113.1"
  local_as       = 65001
  peer_as        = 65002
  description    = "Upstream provider A"

  lifecycle {
    # Don't touch operational state managed by the router
    ignore_changes = [established_count, flap_count]
  }
}

For anything that genuinely cannot be managed declaratively (vendor-specific quirks, one-time migrations), use a null_resource with a local-exec provisioner and document why.

Testing Before You Push

The pattern that reduces production incidents: plan-then-apply in CI, with a mandatory human review of the plan output for anything touching production.

# GitLab CI / GitHub Actions pattern
plan:
  script:
    - terraform init
    - terraform plan -out=tfplan -detailed-exitcode
  artifacts:
    paths: [tfplan]

apply:
  when: manual
  environment: production
  script:
    - terraform apply tfplan

-detailed-exitcode returns exit code 2 when there are changes (rather than 0 = success). This lets the CI pipeline surface “changes pending” as a distinct state from “no changes needed.”

Key Providers for Network Teams

ProviderUse case
netboxSource of Truth objects
panosPalo Alto Networks
junosJuniper Junos
arista_eosArista EOS
aws / azurermCloud networking (VPC, VNet, Transit GW)
cloudflareDNS, WAF, CDN
infobloxIPAM + DNS

Training

The Terraform training at Sphinx-Digital covers all of this: remote state, modules, CI/CD integration, and provider deep-dives including the NetBox and cloud networking providers. 3 days of labs on real AWS infrastructure.