Terraform automates Cisco ACI by letting you declare tenants, VRFs, bridge domains, EPGs, and contracts in HCL code files that are version-controlled, peer-reviewed, and applied through a repeatable init → plan → apply workflow. According to HashiCorp benchmarks, teams using Terraform for ACI provisioning see 5x faster deployment times and 80% fewer configuration errors compared to manual APIC GUI workflows. For CCIE Automation candidates, this is not optional knowledge — section 2.0 of the exam blueprint dedicates 30% to Infrastructure as Code.
Key Takeaway: Nexus-as-Code eliminates the HCL learning curve entirely — you define your ACI fabric in YAML files and let Cisco’s 150+ Terraform sub-modules handle the API translation, making production-grade IaC accessible to network engineers who have never written a line of code.
Why Should Network Engineers Learn Terraform for ACI?
Network engineers managing Cisco ACI fabrics face a fundamental scaling problem: the APIC GUI handles single-tenant provisioning well, but managing 50+ tenants across development, staging, and production environments through point-and-click workflows creates configuration drift, undocumented changes, and rollback nightmares. Terraform solves this by treating your ACI fabric configuration as code — every tenant, VRF, bridge domain, and EPG is declared in a file, tracked in Git, and deployed through an automated pipeline. According to The Network DNA (2026), the shift from imperative scripting to declarative IaC represents the single biggest operational improvement available to data center network teams today.
The business case is straightforward. Manual ACI provisioning through the APIC GUI takes 15-30 minutes per tenant with VRF, bridge domain, and EPG creation. A Terraform apply completes the same work in under 60 seconds. Multiply that across hundreds of change requests per quarter, and the time savings justify the learning investment within the first month. But speed is the least interesting benefit — the real value is in drift detection, peer review, and rollback capability.

Imperative vs. Declarative: Why It Matters for ACI
The critical distinction between a Python script that pushes ACI config and Terraform is idempotency. A Python script that creates a tenant will fail or create a duplicate if you run it twice. Terraform checks the current state first — if the tenant already exists and matches your code, it does nothing. If someone manually changed the VRF name through the APIC GUI, terraform plan shows exactly what drifted and offers to fix it.
| Approach | Behavior on Re-run | Drift Detection | Rollback | ACI Use Case |
|---|---|---|---|---|
| Python + APIC REST API | Fails or creates duplicates | None — must build custom logic | Manual restore from backup | One-off scripts, quick prototyping |
| Ansible ACI Modules | Idempotent per task | Limited — task-level only | Re-run previous playbook | Config pushes, compliance checks |
| Terraform ACI Provider | Idempotent by design | Built-in via state comparison | terraform apply with previous code | Full lifecycle management, multi-env |
| Nexus-as-Code (NAC) | Idempotent + YAML-driven | Built-in + schema validation | git revert + terraform apply | Enterprise-scale ACI automation |
For CCIE Automation candidates specifically, the exam blueprint section 2.0 covers Infrastructure as Code at 30% weight. Terraform with Cisco providers is explicitly listed alongside Ansible. Understanding both tools — and when to use which — is a tested skill.
How Does the Terraform ACI Provider Work?
The Cisco ACI Terraform provider (registry: CiscoDevNet/aci, version 2.x) translates HCL resource declarations into APIC REST API calls using the standard MO (Managed Object) model. According to HashiCorp’s official documentation, the provider supports 90+ resources and data sources covering tenants, networking, security policies, L4-L7 service graphs, and fabric access policies. Every HCL resource maps one-to-one to an ACI managed object class — aci_tenant maps to fvTenant, aci_vrf maps to fvCtx, aci_bridge_domain maps to fvBD.
Here is a minimal working example that provisions a production tenant with a VRF and bridge domain — the three objects you will create most frequently:
# providers.tf
terraform {
required_providers {
aci = {
source = "CiscoDevNet/aci"
version = "~> 2.15"
}
}
}
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-Web"
description = "Production web services tenant"
}
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"
}
Run terraform init to download the provider, terraform plan to see the three resources that will be created, and terraform apply to execute. The entire operation completes in under 10 seconds against a lab APIC.
Authentication Best Practices
Never hardcode APIC credentials in .tf files. Use environment variables:
export ACI_USERNAME=admin
export ACI_PASSWORD=$(vault kv get -field=password secret/apic)
export ACI_URL=https://apic1.lab.local
For production, integrate with HashiCorp Vault or your organization’s secrets manager. The provider reads ACI_USERNAME, ACI_PASSWORD, and ACI_URL environment variables automatically — no provider block credentials needed.
What Is Nexus-as-Code and Why Does It Change Everything?
Nexus-as-Code (NAC) is a Cisco-maintained open-source Terraform module (netascode/nac-aci/aci on the Terraform Registry) that abstracts the raw ACI provider into a YAML-driven data model. Instead of writing HCL resource blocks for every tenant, VRF, bridge domain, and EPG, you write plain YAML — and NAC’s 150+ sub-modules translate that YAML into the correct Terraform resources automatically. According to the Cisco Live BRKDCN-2673 session (2025), NAC reduces the barrier to entry for network engineers who know ACI but have never written infrastructure code.
Here is the same tenant, VRF, and bridge domain from above — written as NAC YAML instead of raw HCL:
# data/tenants.yaml
apic:
tenants:
- name: PROD-Web
description: "Production web services tenant"
vrfs:
- name: PROD-VRF
ip_data_plane_learning: enabled
bridge_domains:
- name: WEB-BD
vrf: PROD-VRF
arp_flood: false
unicast_route: true
subnets:
- ip: 10.1.100.1/24
public: true
shared: false
application_profiles:
- name: Web-App
endpoint_groups:
- name: Web-EPG
bridge_domain: WEB-BD
physical_domains:
- PHY-DOM
The main.tf is minimal — it loads the YAML and passes it to the NAC module:
module "aci" {
source = "netascode/nac-aci/aci"
version = "0.9.3"
yaml_directories = ["data"]
}
That is the entire Terraform configuration. NAC parses the YAML data model, creates the appropriate aci_rest_managed resources for every object, handles dependency ordering, and manages the relationship bindings between tenants, VRFs, bridge domains, and EPGs. For a network engineer who understands ACI concepts but is not a developer, this is the difference between a 2-week Terraform learning curve and a 2-hour one.
NAC Architecture: How YAML Becomes API Calls
Understanding the NAC module architecture helps when troubleshooting. According to Tl10K’s detailed architecture analysis, the flow works like this:
- Your YAML files define the desired ACI state in the
data/directory main.tfloads all YAML files into amodelvariable via theyaml_directoriesparameternac-aciroot module (aci_tenants.tf,aci_access_policies.tf, etc.) parses the model and routes objects to the correct sub-modules- Sub-modules (
terraform-aci-tenant,terraform-aci-vrf, etc.) contain the actualaci_rest_managedresource blocks that make APIC REST API calls - Terraform state records what was deployed, enabling drift detection on subsequent runs
This layered architecture means you never interact with raw API calls or HCL resource blocks — you only modify YAML files. NAC handles the translation.
How Do You Handle Existing ACI Fabrics with Terraform?
Brownfield import is the single most critical step when adopting Terraform for an existing ACI deployment — and the one most commonly skipped, leading to duplicate object errors or worse, silent creation of conflicting configurations. According to the Cisco Live BRKOPS-2142 session (2025), the NAC brownfield import tool (nac-import) automates the process of reading your existing APIC configuration and generating both the YAML data model files and the Terraform state entries.

The Brownfield Import Workflow
- Clone the nac-import tool from GitHub
- Point it at your APIC:
nac-import --url https://apic1.lab.local --username admin - Review the generated YAML —
nac-importreads every managed object and produces data model files matching the NAC schema - Run
terraform initandterraform plan— the plan should show zero changes if the import was complete - Commit to Git — your existing ACI fabric is now under version control
Without this step, writing HCL for objects that already exist causes one of two outcomes: Terraform tries to create duplicates (which APIC rejects with a 400 error), or Terraform creates objects with slightly different attributes that conflict with the existing configuration. Either way, your first terraform apply fails or causes a production incident.
Manual Import for Selective Management
If you only want to manage specific tenants with Terraform (leaving others untouched), use standard terraform import:
# Import an existing tenant into Terraform state
terraform import aci_tenant.prod uni/tn-PROD-Web
# Import an existing VRF
terraform import aci_vrf.prod_vrf uni/tn-PROD-Web/ctx-PROD-VRF
# Verify — plan should show no changes for imported resources
terraform plan
This selective approach is common in organizations where some tenants are managed by automation teams and others are still provisioned manually through the APIC GUI.
How Do You Set Up Remote State for Team-Based ACI Automation?
Terraform state must never live on a single engineer’s laptop in a team environment. The state file (terraform.tfstate) is Terraform’s record of every managed object — without it, Terraform cannot detect drift or plan changes accurately. According to The Network DNA (2026), state locking is the feature that prevents two engineers from running terraform apply simultaneously and corrupting the ACI fabric.
| Backend | State Locking | Best For | Cost |
|---|---|---|---|
| HCP Terraform (Terraform Cloud) | ✅ Built-in | Teams wanting managed runs + approval UI | Free tier available |
| AWS S3 + DynamoDB | ✅ DynamoDB lock | AWS-native environments | ~$1/month |
| Azure Blob Storage | ✅ Blob lease lock | Azure-native environments | ~$1/month |
| GitLab Managed State | ✅ Built-in | Teams already using GitLab CI/CD | Included in GitLab |
Here is an S3 backend configuration — the most common choice for network teams:
terraform {
backend "s3" {
bucket = "aci-terraform-state"
key = "prod/aci/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Separate state files per environment (dev/staging/prod) and per ACI fabric. A terraform destroy on a development state file cannot affect production because they are completely isolated.
How Do You Build a CI/CD Pipeline for ACI Changes?
The ultimate operational improvement from Terraform is treating network changes like software deployments — with automated validation, mandatory peer review, and gated approval before anything touches the fabric. According to the Cisco Live BRKDCN-2607 session (2025), organizations running Terraform through CI/CD pipelines eliminate 80% of ACI misconfigurations caused by manual processes.
Here is a GitHub Actions pipeline for ACI changes:
# .github/workflows/aci-deploy.yml
name: ACI Terraform Pipeline
on:
pull_request:
paths: ['aci/**']
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init -backend=false
- run: terraform validate
- run: terraform fmt -check -recursive
plan:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform plan -out=tfplan -no-color
# Post plan output as PR comment for peer review
- uses: actions/github-script@v7
with:
script: |
const output = `#### Terraform Plan 📋
\`\`\`
${process.env.PLAN_OUTPUT}
\`\`\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
apply:
needs: plan
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # Requires manual approval
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform apply -auto-approve
The environment: production gate means a designated approver must click “Approve” in GitHub before the apply job runs. This is your change management process — automated, auditable, and enforced by the pipeline.
What Are the Common Pitfalls When Starting with Terraform for ACI?
Network engineers transitioning from CLI-based workflows to Terraform consistently hit the same set of issues. According to Tl10K’s design considerations series (2024), the top three mistakes are: skipping brownfield import, storing state locally, and managing all environments from a single state file. Here are the pitfalls and their fixes:
| Pitfall | What Happens | Fix |
|---|---|---|
| Skip brownfield import | terraform apply tries to create existing objects → 400 errors or duplicates | Always run nac-import or terraform import first |
| Local state file | Other team members cannot safely run Terraform; lost laptop = lost state | Configure remote backend with locking on day one |
| Single state for all environments | A dev mistake can destroy production resources | Separate state files per environment and per fabric |
Hardcoded credentials in .tf | Secrets committed to Git → security incident | Use environment variables + Vault integration |
No terraform plan review | Changes applied without peer review → misconfigurations | Enforce plan-before-apply in CI/CD with manual gate |
Monolithic main.tf | 2000-line file that nobody can review or maintain | Split into logical files: tenants.tf, access.tf, fabric.tf |
Provider Version Pinning
Always pin your provider version with a constraint:
required_providers {
aci = {
source = "CiscoDevNet/aci"
version = "~> 2.15"
}
}
The ~> operator allows patch updates (2.15.x) but blocks minor version bumps (2.16.0) that might change resource behavior. Provider updates have historically changed attribute names or default values — a floating version can break your terraform plan output unexpectedly.
How Does This Map to the CCIE Automation Exam?
The CCIE Automation certification (rebranded from DevNet Expert in February 2026) dedicates section 2.0 — Infrastructure as Code — at 30% weight, making it the largest single section on the 8-hour lab exam. According to SMENode Academy (2026), the lab tests Terraform with Cisco ACI as one of the primary IaC scenarios alongside Ansible. Candidates must demonstrate the ability to write, debug, and troubleshoot Terraform configurations under time pressure.
Specific exam tasks that map directly to the skills in this guide:
- Write Terraform HCL to provision ACI tenants, VRFs, and application profiles
- Troubleshoot failed plans by reading provider error messages and APIC API responses
- Use
terraform importto bring existing objects under management - Configure remote state and explain locking behavior
- Integrate Terraform into a CI/CD pipeline with validation and approval gates
For lab preparation, build a practice environment with EVE-NG or Cisco CML running an ACI simulator. The free APIC simulator (available through Cisco DevNet Sandbox) supports all Terraform operations — you do not need physical hardware to practice.
Internal resources for your CCIE Automation journey:
- CCIE DevNet track overview — full blueprint breakdown and study plan
- Your First CCIE Automation Lab: Python, ncclient, and NETCONF — complementary lab skills
- Network Automation Engineer Career Path — career trajectory and salary data
- CCIE Enterprise Infrastructure guide — cross-track study reference
- Cisco ACI VXLAN EVPN deep dive — data center networking context
Frequently Asked Questions
Do I Need Programming Experience to Use Terraform with Cisco ACI?
No. HCL is a declarative configuration language, not a general-purpose programming language — there are no loops, conditionals, or data structures to wrestle with for basic ACI automation. According to The Network DNA (2026), most network engineers become productive with Terraform within a few days. With Nexus-as-Code, you only write YAML — a format most engineers already use for Ansible inventories. Git fundamentals (commits, branches, pull requests) matter more than coding experience.
What Is the Difference Between Terraform and Ansible for ACI Automation?
Terraform manages the full lifecycle of ACI objects declaratively — it creates, updates, and destroys resources to match your code, tracking everything in state. Ansible is imperative and task-oriented — it executes playbooks that push configuration changes. In practice, teams use Terraform for day-0/day-1 provisioning (creating tenants, VRFs, EPGs) and Ansible for day-2 operations (updating QoS policies, pushing ACL changes across existing EPGs). Both tools are tested on the CCIE Automation exam.
What Is Nexus-as-Code and How Does It Simplify Terraform for ACI?
Nexus-as-Code is a Cisco-maintained Terraform module (netascode/nac-aci/aci) with 150+ sub-modules that translates plain YAML files into Terraform ACI resources. Instead of writing individual aci_tenant, aci_vrf, and aci_bridge_domain HCL blocks, you define your entire ACI fabric in YAML and NAC handles the rest. It also includes a brownfield import tool, defaults files for common settings, and schema validation for your YAML data model.
Is Terraform on the CCIE Automation Exam Blueprint?
Yes. Section 2.0 — Infrastructure as Code — covers 30% of the CCIE Automation (formerly DevNet Expert) lab exam according to Cisco’s official blueprint. Terraform with Cisco providers (ACI, IOS-XE, Meraki) is explicitly listed alongside Ansible. The exam tests your ability to write, debug, import, and troubleshoot Terraform configurations under the 8-hour lab time constraint.
How Do I Handle Existing ACI Configurations with Terraform?
Use the nac-import tool from GitHub for bulk brownfield import — it reads your entire APIC configuration and generates both YAML data files and Terraform state entries. For selective management of specific tenants, use standard terraform import commands. The critical rule: never write HCL for ACI objects that already exist without importing them into state first. Skipping this step causes duplicate object errors or conflicting configurations.
Ready to fast-track your CCIE journey? Contact us on Telegram @firstpasslab for a free assessment.
