Ansible: Automate Cisco IOS Configuration

UPDATE: The content of the post is now obsolete for more current up to date please refer to Ansible: Automate Cisco LAN Deployment.

Hi everyone, today we’re going to look into Ansible to deploy networks running Cisco IOS. It is one of the configuration management tools like Puppet and Chef. I’ve used Ansible before to update, upgrade, and install packages and application in Linux Desktop environment. I began learning it again with its introduction ios_config network module used to configure Cisco devices running IOS. It supports not just Cisco IOS but also NXOS, manyXR and ASA and other network vendors such as Juniper and Arista.

Note: In this post, it uses the old playbook and variables, and I updated it using roles which are more simple and scalable in creating tasks and variables.

Disclaimer: Beginner here, but crazy about network automation using Ansible. I’m just glad I found out about Ansible, making an automation tool that easy to understand for some general user like me.

The lab performed in GNS3, using Cisco IOU and Ubuntu Server 14.04 running Ansible 2.1.2

Network Design


In the topology above each of the devices has a management port (the blue dotted line) that connects to the management switch where the Ansible host also connect.

Initial configuration

Before we can automate the configuration, we first need to configure the devices for initial connectivity for the Ansible host able to ssh and push the configuration. Below are the basic configs needed.

! Replace the value in italic format.
enable secret cisco
! This is required in order to generate the key and
! this is the domain where the device belongs to.
ip domain-name
crypto key generate rsa modulus 1024
! This username and password will be use to ssh to this device.
username rey privilege 15 secret cisco
! This enable the device for remote management. The device will use local
! database for authentication by issuing "login local" and it will accept only
! ssh for remote connection by issuing "transport input ssh"
line vty 0 4
 login local 
 transport input ssh 
! Configure the mgmt interface. This must be the same 
! network with the ansible host.
int e1/3
 ip address

Next, refer to the official documentation to install Ansible, (this will be a host controller) on any Linux distribution you prefer. After that, create a directory that includes the ansible.cfg, hostfile, variables, and playbook, rather than modifying the default Ansible configuration which is in etc/ansible/. Below is sample directory for this lab.


First, we need to change the three default configuration of ansible.cfg  for this lab.

transport=paramiko # < paramiko will be use for ssh connection instead of 
# the default which is OpenSSH
host_key_checking=false #< this will not use ssh key in connecting to the 
# devices, instead will username and password, set this true for production 
# environment
hostfile=devices #< defined which file ansible look for hosts.

Next, we will specify our host. This is the file that defined in hostfile under ansible.cfg.

core_sw_01 ansible_host= ansible_hostname=core_sw_01
core_sw_02 ansible_host= ansible_hostname=core_sw_02

acc_sw_01 ansible_host= ansible_hostname=acc_sw_01
acc_sw_02 ansible_host= ansible_hostname=acc_sw_02
acc_sw_03 ansible_host= ansible_hostname=acc_sw_03
acc_sw_04 ansible_host= ansible_hostname=acc_sw_04


rtr_01 ansible_host= ansible_hostname=rtr_01
rtr_02 ansible_host= ansible_hostname=rtr_02

Notice above, the IP address of ansible_host, that’s the IP address of the management interface of each of the device.

Next, we will define our credentials to be used to connect to the devices. This variable is under group_vars/all, meaning that all host were able to use the variable. The username and password were the ones we set during the initial configuration. The host is the IP address or hostname that is configured in the hostfileThe transport is one of the required argument for configuring a network device. Another option is nxapi for Nexus devices.

 host: "{{ ansible_host }}"
 username: rey
 password: cisco
 transport: cli

Next, we will create our host and group variables that will be used by the playbook. Below are sample variables, for complete list of variable and playbook, you can download and refer to it at GitHub repository

# this group variables under group_vars/switches.yml to be use by all switches, 
# that includes core and access switch. 
 - { vlan_id: 15, name: voice15} 
 - { vlan_id: 55, name: data55}

# this group variables under group_vars/core.yml will be use by
# core_sw_01 and core_sw_02.
 - name: vlan15
   ip: "{{ vlan15.ip }}"
   pri: "{{ vlan15.pri }}"

# this host variable under host_vars/core_sw_01.yml to be use by core_sw_01.
   pri: 110
# this host variable under host_vars/core_sw_02.yml to be use by core_sw_02.
   pri: 90

Next, we can now create a playbook and use the variables stated above.

The configuration below is the sample task in the playbook that will create a VLANs in the device and its corresponding VLAN name.

- name: core switch configurations
  hosts: core
  gather_facts: no
  connection: local

  - name: create vlans
      provider: "{{ provider }}"
      lines: name {{ }}
      parents: vlan {{ item.vlan_id }}
    with_items: "{{ vlans }}"

For better visual representation refer to the figure below.


In the above playbook, the ios_config is the name of Ansible module for configuring Cisco device that is running IOS. Please see the official documentation for the Ansible Cisco module.

Notice the with_items above that is one of the  Loops in Ansible called standard loop. It will iterate the content of the variable, in this case, the vlans variable which is in group variable named switches, ( refer to the hostfile)  meaning that all the devices under the group switches can use it, that includes the device under core and access group.

Next playbook will configure the device Switch Virtual Interface (SVI) and its IP address and subnet mask.

- name: switch virtual interface
    provider: "{{ provider }}"
    - ip add {{ item.ip }} {{ item.mask }}
    - delay 200
    parents: interface {{ }}
  with_items: "{{ svi_int }}"

For better visual representation refer to the figure below.


This time, the task used a group variable and it calls two host variable under core_sw_01 and core_sw_02. It used the same type of loop with_items. I know that there is a lot of ways to construct the variables, and I may be wrong with this one. But in this lab, what I’ve done was, I defined the unique variables on each of the devices, like IP addresses, HSRP priority, STP priority, etc., after that, create group variables then reference those unique variables. An example in the task below, it is an HSRP configuration on core_sw_01 and core_sw_02, it set a virtual IP (common value to two core switch) and priority ( unique value ) that determine which device will be the active or standby router. So the unique value here is the pri under  host_vars, then reference it to the group variable named core.yml (includes core_sw_01 and core_sw_02) under group_vars. Notice that also, it used same variable ( svi_int ) and just call whatever attribute is needed in the task.


Right now, I’m reading some of the techniques or best practices, on how to build variables that can scale, optimized and simple to manage.

Below is a video that runs the full playbook ( which is also available on my GitHub ) to configure the devices that are in the topology. It involves a little bit of troubleshooting using the Ansible ios_command module ( basically a show command in Cisco IOS) and a simple, convenient playbook to configure additional configuration without writing a full blown playbook. The video was longer that I expected, but you can skip through just to get the idea, and sorry I don’t have a microphone.


Ansible is a very powerful tool to automate networks and there is a lot of advantages in using it like, increase efficiency and effectiveness and reduce human errors in deploying and maintaining large networks. That is because before you push a configuration to the device, you have a good overview what would be the outcome of the command. Very useful when you have to maintain hundreds of switches, and you have a lot of network projects. Let’s say you are an IT service provider that provide network deployments, what you can do is build the playbook during the planning and designing phase, and on the actual deployment, just need to configure basic connectivity, and automate the rest of the deployment.

Thanks for stopping by.

If you need help regarding the topic, please don’t hesitate to leave a comment or email me.



3 thoughts on “Ansible: Automate Cisco IOS Configuration

  1. Hello,

    Thanks for the greate info I only have one question when I execute the playbook show.yml I get the error
    The offending line appears to be:\n\n\n – name: show commands\n ^ here\n”}

    Where can the issue be?



  2. Hello Reynold,

    THanks for you time here is my playbook

    – hosts: core
    gather_facts: true
    connection: local

    – name: show run

    – show run
    host: “{{ ansible_host }}”
    username: cisco
    password: cisco
    register: config

    – name: save output to /home/juraj/
    content: “{{ config.stdout[0] }}”
    dest: “/etc/ansible/backups/show_run_{{ inventory_hostname }}.txt”


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s