Skip to content

[My Journey to CCIE Automation #6] Automating Cisco ACI Deployments with Terraform, Vault, and GitLab CI

Bjørnar Lintvedt 2 oktober, 2025
My journey continues

👋 Hi, I’m Bjørnar Lintvedt

I’m a Senior Network Consultant at Bluetree, working at the intersection of networking and software development.

As mentioned in my first blog post, I’m preparing for the CCIE Automation lab exam — Cisco’s most advanced certification for network automation and programmability. I’m documenting the journey here with weekly, hands-on blog posts tied to the blueprint.

Link to my GitLab Repo

 

Blog post #6

After working with pyATS and CI/CD in blog post #5, I wanted to dive deeper into infrastructure as code using Terraform, and integrate it with GitLab CI.

This week I explored Terraform to deploy and manage Cisco ACI fabric resources in a stateful and repeatable way, and integrated Vault to manage secrets in my Nautix app.

 

Why Terraform?

Terraform allows us to describe infrastructure declaratively. It’s perfect for:

  • Managing ACI tenants, VRFs, and EPGs as code

  • Handling dependencies between resources automatically

  • Tracking state to know exactly what’s deployed

  • Using loops and variables for repeatable, parameterized deployments

  • Integrating secrets securely (Vault)

Instead of manually pushing configurations, Terraform lets your code understand and manage the network state.

 

Why Vault?

Vault provides a secure way to manage secrets and credentials in automation pipelines. In this project, it allows us to:

  • Store ACI usernames and passwords securely

  • Provide credentials dynamically to Terraform without hardcoding them

  • Rotate secrets easily without touching code

  • Control access to sensitive information per environment or service

Instead of storing credentials in .tfvars or Git, Vault makes sure secrets never leak and automation pipelines can safely access what they need.

 

This Week’s Project

I created a Terraform project to deploy ACI resources, integrated into GitLab CI:

  • Variables (aci.auto.tfvars) – Centralized definitions for tenants, VRFs, application profiles, and endpoint groups.

  • GitLab CI (.gitlab-ci.yml) – Orchestrates Terraform runs in a pipeline.

  • Vault service – Docker Compose file spins up Vault and other required services locally.

 

Pipeline Flow

1. The pipeline is triggered by creating a pipeline

  • With the required JOB_METHOD and environment variables.

2. Terraform Plan Stage

  • Runs automatically if JOB_METHOD is set to "terraform"

  • Initializes Terraform

  • Generates a plan file (tfplan) showing what will be created or updated



3. Terraform Deploy Stage

  • Runs manually after verifying the plan

  • Applies the plan and provisions the Cisco ACI infrastructure

This staged approach ensures safe deployments and gives you an opportunity to review changes before they are applied.

 

 

Implementation

Here’s the folder structure:

📂 pipelines/jobs/setup_aci/

  • main.tf – Terraform resources, loops, and dependencies

  • aci.auto.tfvars – Variables and credentials for ACI deployment

Also updated:

  • .gitlab-ci.yml – Orchestrates Terraform in CI/CD pipeline

  • docker-compose.yml – Spins up Vault and other services for local testing

 

 

How It Works

Let’s break it down step by step.

 

1. Gitlab CI

The .gitlab-ci.yml ties the workflow together and determines which stages run based on the JOB_METHOD variable.

  • Ensure that Terraform is installed in the Gitlab runner.

  • The first stage runs automatically (terraform plan) and produces a plan file. 

  • The deploy stage (terraform apply) runs manually and provisions the ACI resources based on the plan.

 


 

2. Terraform

The project consists of main.tf and aci.auto.tfvars.

  • Providers: Cisco ACI provider for resource creation and Vault provider for secure credentials.
  • Vault integration: Use VAULT_TOKEN environment variable (export TF_VAR_VAULT_TOKEN=root-token) to fetch secrets dynamically.
  • Variables:
    • TENANT_NAME: Name of the ACI tenant ("NAUTIX")

    • APPLICATIONS: List of applications with names, descriptions, and endpoint groups

    • VRFS: List of VRFs to create under the tenant (["RED", "BLUE"])

 
 
  • Tenant
    • Creates an ACI tenant with the name "NAUTIX".
  • Application profiles
    • Creates one application profile per application in the tenant.

    • Uses the for_each loop so Terraform dynamically creates profiles for:

      • bluetree.no

      • upstacked.com

  • Endpoint groups
    • Creates EPGs for each application.

    • Loops through all endpoint_groups from locals.endpoint_groups.

    • Uses a key combining app_name and epg_name to ensure unique map keys for for_each

  • VRFs
    • Creates VRFs for the tenant, one for each name in VRFS.

    • Converts the list to a set to ensure unique entries.

 


 
3. Vault

A new Vault service is added to the Docker Compose file to provide secure credentials to Nautix without exposing them in code.

 


 
Why This Matters

Instead of manually configuring ACI:

✔ Deployments are repeatable and version-controlled
✔ Loops and variables make scaling easy
✔ Secrets are protected with Vault
✔ Dependencies between tenants, VRFs, and EPGs are automatically handled
✔ Terraform and GitLab CI now manage infrastructure safely

 

 

 

Nautix architecture

 


 

📅 What’s Next
In post #7 I will focus on Model-driven-telemetry:
Blueprint item 3.4 Design a model-driven telemetry solution based on given business and technical requirements by using gNMI dial-in, gRPC dial-out, and NETCONF dial-in
Blueprint item 3.5 Create YANG model-driven telemetry subscriptions
    3.5.a Identify model elements and cadence
    3.5.b On-change or event drive
    3.5.c Optimize frequency
    3.5.d Dial-out subscription
    3.5.e Secure telemetry streams
    3.5.f Confirm data transmission
    3.5.g Identify network issues and make changes

 

🔗 Useful Links

 

Blog series