Auotmating Cisco IOS devices with Ansible

4 minute read

What is Ansible?

Ansible is an IT automation software used to simplfy routine tasks such as provisioning, configuration, app deployment, security automation, and much more. The benefits of Ansible are:

  • Ease of use due to playbooks written in YAML language
  • It is Agentless. It uses the SSH protocol to push to your client devices
  • Ansible is idempotent – only accomplish what needs to be done, and don’t change what doesn’t

In this post we will go over a simple configuration of a Cisco IOS device using Ansible running on a Ubuntu VM and a Cisco device running in GNS3.

Ansible and Networking

Due to Ansible’s ability to push configuration changes using SSH, Ansible can be used on almost any networking device. Ansible has modules written for many existing network products such as Cisco, Juniper, Palo Alto, etc. Ansible’s modules are pre-written unites of code designed to accomplish certain tasks within a playbook. Think of them as plugins.

Preparing Ansible to Configure a Cisco Router

Before we can begin we will have to set up our Ansible directory. The recommonded best practice for setting up the directory structure can be found in Ansible’s docs: Best Practices however for this post, our directory is much simpler. I prefer to set up my directory like the one below:

ansible_project/              # Top level ansible folder
    group_vars/               # Variables to be called from playbooks
    roles/                    # All roles
        role-a                # Role
        role-b                # Role
        ...
    Inventory/                # Folder for inventories
        hosts                 # Hosts to configure defined here
    playbooks/                # All playbooks below here
        plabook.yml           # Example playbook
    ansible.cfg               # Site specific config

First we have to define our host that we want to configure in a hosts file. You can name it whatever you want. We define a group of hosts disgnated in brackets such as [cisco]. This allows us to call multiple hosts at once by defining one group in our playbook. We can define hosts by IP, by “Router1 ansible_host=192.168.56.130”, or by hostname if DNS is configured. Example:

[cisco]                               # Host Group
192.168.56.130                        # Host defined by IP
Router1 ansible_host=192.168.56.130   # Defined by naming convention
router1.example.com                   # Define by hostname

Ansible also recommends specifying your host groups connection and credential information in the host file in the form of [cisco:var] like below. Here we need to identify the information Ansible will use when attempting to connect to the device using SSH:

[cisco:vars]                     # Host group variables 
ansible_network_os=ios           # The type of Operating System
ansible_ssh_user=admin           # SSH Username
ansible_password=password        # SSH Password
ansible_become=yes               # Permissions upgrade 'yes' or 'no'
ansible_become_method=enable     # Enter enable mode
ansible_become_password=password # Enable password

Writing a Playbook to Configure a Device

Once our inventory is defined with the hosts we want to run Ansible against, we have to create a playbook comprised of tasks to complete. For this example we will be configuring a banner on a Cisco IOS device.

To begin, I create a banner_playbook.yml file under the playbooks directory

---                                     #YAML files are designated by the 3 --- dashes
- name: Configure motd and banner       # Purpose of the playbook
  hosts: cisco                          # Define the group of [hosts] that exist in the inventory
  connection: network_cli               # Connection type- network_cli for IOS devices
  gather_facts: no    

  tasks:                                # Anything below this point are tasks to be run

# ios_banner module used to define banners and messages of the day on Cisco IOS devices
# Banner choices: login / motd / exec / incomin / sip-ppp
# text can be defined here or as a variable called from another place.
    - name: CONFIGURE LOGIN BANNER
      ios_banner:                                 # The name of the module to use
        banner: login                             # The type of banner such as login or exec
        text: |                                   # The text to be used for the banner
          Warning: Authorized employees only. 
          All others will be in trouble.
        state: present                            # Current existential state of the banner

# iosxr_banner module used for IOSXR Cisco Devices
# Banner choices: login / motd
    - name: configure the login banner
      iosxr_banner:
        banner: login
        text: |
          this is my login banner
          that contains a multiline
          string
        state: present

# nxos_banner module for Cisco NXOS devices
# Banner choices: exce / motd
    - name: configure the exec banner
      nxos_banner:
        banner: exec
        text: |
          this is my exec banner
          that contains a multiline
          string
        state: present

Key points about the playbook

  • YAML format is white space sensitive
  • This playbook includes 3 modules, one for Cisco IOS, IOSXR, and NXOS
  • Use # signs to comment out lines you want Ansible to ignore
  • The banner text can be pulled from a variable in another file or a document in another directory as well

Running the playbook

With our hosts, host connection, & login informaiton defined and our banner configuration playbook written we can run the playbook.

To run a playbook issue from the main Ansible dir. ansible-playbook -i inventory/hosts playbook/banner_configuration.yml

  • ansible-playbook; The command used to run a playbook
  • -i option is used to define the hosts file location if not set in ansible.cfg
  • playbook/ is used to define the location of the playbook if we are not in the playbooks dir.

The output should look similiar to this minus the purple text I recieved due to outdated versions.

My Image