The integration of Ansible into the Cisco Application Centric Infrastructure (ACI) ecosystem represents a paradigm shift from traditional manual CLI-based configuration to a sophisticated Infrastructure as Code (IaC) model. By leveraging the cisco.aci collection, network engineers can transition from executing individual API calls or manual GUI entries to deploying comprehensive, version-controlled network fabrics. This approach allows for the programmatic definition of tenants, VRFs, bridge domains, and other critical ACI objects, ensuring that the fabric remains consistent, scalable, and free from the configuration drift common in large-scale data center environments.
The Architecture of the cisco.aci Collection
The ansible-aci project provides a dedicated Ansible collection designed specifically for managing and automating the Cisco ACI environment. This collection is not merely a set of scripts but a comprehensive framework consisting of specialized modules and plugins that map directly to the ACI object model.
Core System Requirements
To ensure the stability and performance of the automation framework, specific versioning requirements must be met.
- Ansible v2.16 or newer: This version provides the necessary engine capabilities to handle the complex data structures and collection mechanisms used by Cisco ACI.
- Python v3.11 or newer: Python serves as the core base of Ansible; version 3.11 ensures compatibility with the latest asynchronous libraries and data handling methods required for REST API interactions with the APIC.
Installation Methodologies
There are multiple pathways to deploy the cisco.aci collection, depending on whether the user requires a stable release or the latest development features.
Using Ansible Galaxy
The primary method for installation is via the Ansible Galaxy command-line tool. This allows users to pull the latest stable version from the public repository.
ansible-galaxy collection install cisco.aci
For enterprises managing multiple environments, it is recommended to use a requirements.yml file. This file allows for version pinning and ensures that all team members are using the exact same collection version, which is critical for avoiding deployment discrepancies.
The requirements.yml file should follow this format:
yaml
collections:
- name: cisco.aci
The installation using the requirements file is executed via:
ansible-galaxy collection install -r requirements.yml
Manual Installation from Source
For developers or early adopters who need the latest master branch features, installation can be performed directly from the GitHub repository. This process involves cloning the repository and building the collection locally.
- Clone the repository:
git clone https://github.com/CiscoDevNet/ansible-aci.git - Navigate to the directory:
cd ansible-aci - Update to the latest master:
git pull origin master - Build the collection:
ansible-galaxy collection build --force - Install the built package:
ansible-galaxy collection install cisco-aci-* --force
Alternatively, users can navigate to the Ansible-ACI Actions page and download the latest CI build artifact. These artifacts are usually suffixed with the compatible Ansible version (e.g., collection-stable-2.17). Because these are zip files containing a tar.gz file, they must be unzipped using a terminal or console before they can be utilized by the Ansible engine.
Maintenance and Upgrades
Collections installed via Ansible Galaxy are not automatically upgraded when the main Ansible package is updated. This decoupling ensures that a package update does not inadvertently break network configurations due to a module change. To manually update the collection to the latest version, the following command is used:
ansible-galaxy collection install cisco.aci --upgrade
Users can also target a specific version for stability reasons, using the following syntax to install version 1.0.0:
ansible-galaxy collection install cisco.aci:==1.0.0
Advanced Playbook Design and Variable Management
In a production ACI fabric, creating individual YAML files for every tenant is inefficient and unscalable. If a requirement exists to create 100 tenants, manual file creation becomes a catastrophic waste of resources. Ansible solves this through the use of templates and a sophisticated variable precedence system.
Jinja2 Templating and Dynamic Data
Ansible utilizes Jinja Templates, which are deeply integrated into the Python core. This allows developers to use variables within YAML files, turning a static configuration into a dynamic template. For instance, a task to create a tenant does not need to hardcode the tenant name; instead, it uses the {{ tenant_name }} placeholder.
The technical implementation for a tenant creation task looks as follows:
yaml
- name: CREATE ACI TENANT
cisco.aci.aci_tenant:
tenant: "{{ tenant_name }}"
descr: "{{ descr }}"
host: "{{ inventory_hostname }}"
username: "{{ username }}"
password: "{{ password }}"
validate_certs: false
Variable Precedence and Hierarchy
Ansible employs a strict precedence system to determine which variable takes priority when the same variable is defined in multiple locations. This prevents configuration conflicts and allows for "default" settings that can be overridden by "specific" settings.
The hierarchy follows this logic: - Role defaults directory: Lowest precedence. - Playbook global_vars/all directory: Overrides role defaults. - Role vars directory: Overrides both global vars and role defaults.
This structure allows a network architect to define a global username for the entire fabric in group_vars/all, but override it for a specific site or role in the role-specific vars.
Optimizing Playbook Structure with module_defaults
To avoid the repetition of authentication credentials (hostname, username, password) in every single task, Cisco has introduced the module_defaults capability. This allows the definition of a central dictionary of key/value pairs that are automatically passed to every module in the collection.
Implementation of module_defaults
By defining module_defaults at the playbook level, the structural complexity is reduced, and readability is increased. The authentication and connection elements are defined once and inherited by all subsequent tasks.
The following example demonstrates a main playbook (site.yml) located in ~/ltrdcn-3225/ansible/playbooks/aci:
```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 ```
In this configuration, the group/cisco.aci.all section ensures that any module within the cisco.aci namespace will use these credentials, removing the need to specify them in the roles/apic/tasks/main.yml file.
Complex Orchestration: Loops, Filters, and REST Integration
For complex data structures, such as nesting VRFs within tenants or Bridge Domains within VRFs, simple variables are insufficient. Ansible provides loop constructs and filters to handle these relationships.
Iterating with subelements and from_yaml
When dealing with a list of tenants, where each tenant contains a list of VRFs, the subelements filter is used. This filter allows Ansible to flatten a nested list so that the loop can iterate through each VRF individually. Additionally, the from_yaml filter is utilized to convert YAML data structures into a list of dictionaries that Ansible can process.
Example of VRF creation using loops:
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
Handling Complex Data with Jinja2
In scenarios where complex configuration data is defined, inline Jinja templating can be used to generate simpler data structures. This is often combined with the ansible.builtin.set_fact module.
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 ... %}
The aci_rest Module as a Fallback
In instances where a specific high-level Ansible module for a particular ACI object is unavailable, Cisco provides the aci_rest module. This is a powerful, low-level tool that allows users to send any valid ACI configuration object directly to the APIC via the REST interface. This ensures that 100% of the ACI API is accessible, even if a dedicated module has not yet been developed for a specific feature.
Authentication Strategies: Password vs. Signature-Based
Security is paramount in ACI management. While traditional username/password authentication is common, Cisco supports signature-based transactions for increased security and performance.
Signature-Based Authentication Technicals
Signature-based transactions utilize X.509 certificates (public keys) assigned to local users in the APIC. When a client initiates a request, they use a corresponding private key to sign the API request using the SHA-256 algorithm.
The technical advantages are twofold:
- Security: The SHA-256 digest prevents man-in-the-middle tampering attempts.
- Performance: Because the identity is validated via the signature, the aaaLogin method is no longer required for each post. This eliminates the overhead of the login process for every single transaction, resulting in significant performance gains.
Implementation of Signature-Based Playbooks
When using signature-based authentication, the playbook must reference the private key. The following example demonstrates a performance-testing loop creating multiple tenants:
```yaml
- name: create N tenants with a loop
hosts: dot34
connection: local
vars:
acicreds: &acilogin
hostname: '{{ inventoryhostname }}'
username: '{{ ansibleuser }}'
validatecerts: no
useproxy: no
private_key: key.pem
myState: "present"
tasks:
- name: tenant loop acitenant: <<: *acilogin tenant: "{{ 'tenantLoopUser-%02x' | format(item) }}" description: performance testing state: '{{ myState }}' loop: "{{ range(1,6) }}" ```
In this snippet, the &aci_login anchor is used to create a reusable block of credentials, and the <<: *aci_login syntax injects those credentials into the aci_tenant module.
Inventory Management and Host Configuration
The inventory file is the foundation of any Ansible deployment, as it maps the logical groups of devices to their actual network addresses.
Inventory File Structure
While the default location for the inventory is /etc/ansible/hosts, it is a best practice to use a local file and reference it with the -i flag (e.g., -i hosts.yml). This allows for environment-specific inventories to be versioned alongside the playbooks.
A typical ACI inventory file (hosts.yml) located at ~/ltrdcn-3225/ansible/playbooks/aci is structured as follows:
```yaml
# hosts file for Ansible playbook
all: children: aci: hosts: apic: ansible_host: 10.0.226.41 ```
This structure classifies the APIC under the aci group, allowing the operator to target the entire ACI fabric or specific controllers using group-based addressing.
Technical Specification Summary
The following table summarizes the technical requirements and operational parameters for the cisco.aci environment.
| Component | Requirement / Value | Purpose |
|---|---|---|
| Ansible Version | v2.16+ | Core Engine |
| Python Version | v3.11+ | Runtime Environment |
| Installation Tool | ansible-galaxy |
Collection Management |
| Template Engine | Jinja2 | Dynamic Variable Injection |
| Auth Method | SHA-256 / X.509 | Signature-Based Security |
| Fallback Module | aci_rest |
Generic REST API Access |
| Connection Type | local or ansible_host |
APIC Communication |
Conclusion
The utilization of the cisco.aci collection transforms the APIC from a target of manual configuration into a programmable entity. By implementing module_defaults, network engineers can strip away the noise of repetitive authentication, allowing the playbook to focus on the desired state of the network. The combination of Jinja2 templating for dynamic scaling and the subelements filter for managing complex object hierarchies ensures that the ACI fabric can scale from a few tenants to hundreds without a linear increase in administrative effort. Furthermore, the transition to signature-based authentication provides a critical intersection of security and performance, removing the latency of the aaaLogin process while securing the management plane against tampering. This comprehensive framework allows for a robust, repeatable, and audited approach to data center orchestration.