The convergence of Software Defined Networking (SDN) and Infrastructure as Code (IaC) has fundamentally transformed the way data center fabrics are deployed and managed. At the center of this evolution is the Cisco Application Centric Infrastructure (ACI), a policy-driven architecture that abstracts the network into a fabric of leaf and spine switches managed by a centralized Application Policy Infrastructure Controller (APIC). While the APIC provides a robust Graphical User Interface (GUI) and a programmatic REST API, the scale of modern enterprise environments necessitates a transition from manual configuration to automated orchestration. Ansible, a powerful Python-based automation engine, serves as the primary catalyst for this transition, allowing engineers to treat network configuration as versionable, testable, and repeatable code.
The integration of Ansible with Cisco ACI allows for the programmatic definition of tenants, Virtual Routing and Forwarding (VRF) instances, bridge domains, and endpoint groups, effectively removing the human-error element from the provisioning process. By leveraging the Cisco ACI Ansible collection, operators can move away from "screen-scraping" or manual API calls and instead utilize declarative playbooks. This approach ensures that the state of the fabric is consistent across multiple pods and sites, facilitating a "Network-as-Code" philosophy where the desired state of the network is defined in YAML files and enforced by the Ansible engine.
The Architectural Foundation of ACI Automation
The interaction between Ansible and the Cisco ACI fabric is predicated on the ability of the automation engine to communicate with the APIC. This communication is handled via the ACI REST API, which operates over standard HTTP and HTTPS protocols. The APIC acts as the single point of management, translating the high-level intents delivered by Ansible into the low-level configurations required by the physical switches.
To establish a secure and stable connection, two primary authentication methods are supported:
- Username and password combinations, which provide a standard credential-based access method.
- Signature-based transactions, which utilize per-user X.509 certificates for enhanced security and non-repudiation.
The choice of authentication method has direct consequences on the client-to-APIC connection behavior. For instance, certificate-based authentication provides a higher security posture suitable for zero-trust environments but requires a more complex Public Key Infrastructure (PKI) management process. In contrast, username/password authentication is simpler to implement but requires rigorous secret management, typically via Ansible Vault, to avoid exposing credentials in plain text.
Advanced Module Implementation and the aci_rest Fallback
Cisco provides a comprehensive suite of native Ansible modules designed to manage specific ACI objects. These modules allow users to define the state of a resource (e.g., present or absent), and Ansible ensures the fabric reaches that state. However, due to the rapid evolution of ACI features, there may be instances where a specific native module for a new or niche feature has not yet been developed.
To solve this gap, Cisco has developed the aci_rest module. This specialized tool allows an engineer to send specific ACI configuration objects directly into the fabric via the REST interface. This ensures that automation is never completely blocked by the absence of a dedicated module, providing a generic interface to any API endpoint exposed by the APIC.
For those seeking pre-built automation patterns, the Ansible-recipes-for-ACI repository on GitHub serves as a critical resource. This repository provides seasoned users with comprehensive examples to provision ACI resources using native modules wherever possible. Key examples found in these recipes include:
- Complete configuration of interfaces, including interface policies, VLAN pools, and domains.
- Comprehensive multi-tier tenant configurations.
- Implementation of various types of L3outs for external connectivity.
- Configuration of essential fabric-wide services such as Network Time Protocol (NTP), Domain Name Services (DNS), and Border Gateway Protocol (BGP) Route Reflectors.
Mastering Data Structures and Dynamic Configuration
In a production environment, creating individual YAML files for hundreds of tenants is computationally inefficient and administratively impossible. To overcome this, Ansible leverages Jinja2 templating and advanced filters to handle complex data structures.
The use of Jinja Templates allows variables to be injected into playbooks, transforming a static configuration into a dynamic template. This is particularly useful when deploying identical structures across different environments (e.g., Dev, Stage, Prod). The implementation involves using double curly braces {{ }} to denote variables, which Ansible resolves at runtime based on the provided inventory and variable files.
To handle the complexity of ACI's hierarchical nature (Tenant > VRF > Bridge Domain), Ansible employs specific filters and constructs:
- The
subelementsfilter: This is used to iterate over nested lists, such as iterating through all VRFs within multiple tenants. - The
from_yamlfilter: This is critical for converting YAML data structures into a list of dictionaries that Ansible can process. - Inline Jinja templating: This allows the engineer to generate simplified data structures from complex configuration data on the fly.
An example of this logic in practice can be seen in the creation of VRFs and Bridge Domains. When creating VRFs, the loop construct combined with the subelements filter allows the playbook to traverse the tenant list and create every VRF associated with those tenants in a single task.
yaml
- name: CREATE ACI TENANT VRF(S)
cisco.aci.aci_vrf:
tenant: "{{ item.0.name }}"
vrf: "{{ item.1.name }}"
state: present
delegate_to: localhost
loop: "{{ tenants | subelements('vrfs') }}"
loop_control:
loop_var: item
Similarly, generating Bridge Domains often requires the set_fact module and the from_yaml filter to process a block of YAML data into a format usable by the ACI modules.
yaml
- name: GENERATE BRIDGE DOMAIN(S)
ansible.builtin.set_fact:
bridge_domains: "{{ _bridge_domains | ansible.builtin.from_yaml }}"
vars:
_bridge_domains: |-
{% for tenant in tenants | default([]) %}
{% for vrf in tenant.vrfs | default([]) %}
{% for bd in
Optimization via module_defaults and Variable Precedence
To avoid the repetitive definition of connection parameters—such as the hostname, username, and password—in every single task, Cisco ACI modules support the module_defaults feature. This allows the administrator to define authentication and connection elements in a central location within the playbook, which is then passed to every module in the group.
The module_defaults section is a dictionary that contains key/value pairs. By defining these under group/cisco.aci.all, the playbook becomes significantly more readable and easier to maintain.
Example of a streamlined site.yml playbook using module_defaults:
```yaml
main playbook
- name: APIC Tenant Configuration playbook
hosts: apic
gatherfacts: false
moduledefaults:
group/cisco.aci.all:
hostname: "{{ansiblehost}}"
username: "{{ username }}"
password: "{{ password }}"
validatecerts: false
use_ssl: true
roles:- role: apic
```
- role: apic
Understanding variable precedence is equally vital for the ACI engineer. Ansible follows a strict hierarchy to determine which value to use when a variable is defined in multiple places. The precedence generally follows this flow:
- Role defaults: The lowest priority; these are the baseline values.
- Playbook global variables (
global_vars/all): These override role defaults. - Role variables (
role vars): Variables defined within the specific role's vars directory override both global variables and role defaults.
Inventory Management and Playbook Structure
For a successful ACI deployment, the inventory file must be correctly configured to map the Ansible control node to the APIC. While the default location is /etc/ansible/hosts, it is best practice to use a local hosts.yml file and invoke it using the -i hosts.yml command.
The inventory allows for the classification of devices into groups, enabling the operator to target specific sets of controllers or switches. A typical ACI inventory structure looks like this:
```yaml
# hosts file for Ansible playbook
all:
children:
aci:
hosts:
apic:
ansible_host: 10.0.226.41
```
Following Ansible best practices, the directory structure should be organized into roles. This promotes reuse and modularity. Instead of a single massive playbook, the configuration is split into roles (e.g., an apic role) containing tasks, handlers, and variables. The main playbook then simply calls these roles.
Real-World Deployment Workflow: The ATC Lab Perspective
In professional Proof of Concept (POC) environments, such as those managed by the Advanced Technology Center (ATC), the deployment of a fabric involves a transition from physical setup to automated configuration.
The initial phase involves the Cisco Integrated Management Controller (CIMC), often referred to as "the Sim-See," which is used for the initial hardware setup. Once the APIC is reachable and the fabric is physically healthy, the automation phase begins.
In a high-scale deployment, a tool like Ansible Tower (now AWX/Controller) is utilized. Within Tower, a "Job Template" (such as "ACI - Deploy Fabric") is created. This template manages the execution of multiple playbooks—in some professional environments, as many as 18 distinct playbooks—to complete the full fabric configuration.
The workflow typically follows these stages:
- Variable Definition: Using a text editor (e.g., Sublime Text), the engineer modifies the YAML templates with site-specific variables.
- Job Trigger: The Job Template is launched in Ansible Tower.
- Execution: Ansible iterates through the playbooks, moving from basic tenant creation to complex L3Out and BGP configurations.
- Verification: Connectivity is verified from a host (e.g., a Windows 10 host) to the default gateway and subsequently to external targets like Google DNS (8.8.8.8) to ensure the L3Out is functioning correctly.
An example of a basic tenant creation task using variables:
yaml
- name: CREATE ACI TENANT
cisco.aci.aci_tenant:
tenant: "{{ tenant_name }}"
descr: "{{ descr }}"
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: false
Technical Specifications Summary
The following table summarizes the technical components and their roles within the ACI-Ansible ecosystem.
| Component | Function | Technical Detail |
|---|---|---|
| APIC | Management Controller | Provides REST API for all fabric configurations |
cisco.aci Collection |
Ansible Modules | Native Python modules for ACI object management |
aci_rest Module |
Generic API Interface | Used when native modules are unavailable |
| Jinja2 | Templating Engine | Handles dynamic variable injection and loops |
subelements |
Ansible Filter | Facilitates iteration over nested ACI objects |
module_defaults |
Configuration Optimization | Centralizes authentication and connection settings |
| Ansible Tower | Orchestration Layer | Manages Job Templates and playbook execution |
Conclusion: Analysis of the Automated Fabric
The transition from manual APIC configuration to an Ansible-driven workflow represents a shift from operational reactivity to strategic orchestration. By leveraging the cisco.aci collection and the aci_rest module, organizations can eliminate the inconsistencies inherent in manual entry. The use of module_defaults and sophisticated Jinja2 templating allows for a scalable architecture that can grow from a single pod to a multi-site fabric without a linear increase in administrative overhead.
The true power of this approach lies in the ability to treat the network as a software project. When the network configuration is stored in YAML and managed via Git, every change is tracked, every deployment is repeatable, and the disaster recovery time is reduced from days to minutes. The integration of Ansible Tower further matures this process by providing an audit trail and a controlled environment for executing complex, multi-playbook deployments. Ultimately, the combination of Cisco ACI and Ansible transforms the data center from a collection of hardware into a flexible, programmable asset.