As a listener to the podcast you’ve probably heard about Ansible once or twice already. In short Ansible is a simple IT automation tool. It’s often mentioned together with Puppet, however a big difference is that Ansible is agentless. Using Puppet assumes that you have a Puppet agent installed on the nodes that you want to manage. While that works on some network devices, with most network equipment it’s not possible to install a Puppet agent (yet). Ansible on the other hand doesn’t have any agents, instead it connects through SSH which is assumed to be up and running on the target machines. At first glance this might seem perfect; Ansible doesn’t require any agents and it runs over SSH, the same as all of our network equipment does. However there’s a small ‘but’ in terms of how Ansible works.
How Ansible works
The actual work on remote devices is done by Ansible modules. What happens is that you run Ansible from your server which connects to the target device and copies the module file to the remote device, the module is then executed locally on the remote host. Typically these modules are written in Python. The problem here is that even if we can copy the module file to a network device, there’s a good chance that you don’t have Python installed on that network device. What this means is that you can’t use Ansible out of the box with networking equipment. In fact the install docs tells us that Python is a requirement on the managed nodes.
Using Ansible with network devices
Still you have the option to use the raw module just to execute commands on a device.
While you can gather some information it doesn’t really help you that much. Something more useful is that Ansible has a really powerful the templating system which can be used to create configurations for your network devices. However Ansible uses Jinja2 to handle templates and if you learn some basics about Python and Jinja2, you don’t need Ansible to do this.
So how could Ansible work with a Cisco switch? If you browse through the Ansible module index you actually see some networking equipment. For example there’s support for F5 and Citrix load balancers. Ansible even support Windows servers which generally don’t have an SSH server running. It turns out that Ansible actually doesn’t require SSH and a lot of modules use different protocols. SSH is just the default connection type, aside from SSH you can tell Ansible to run a task in local mode where the module script would be run directly from the Ansible server. This is the way the F5 modules operate, when they are run it’s from the server and the connection is then done through https.
What this means is that we can use whichever protocol we want to from Ansible. For the most part this still doesn’t help us much, however some network devices are starting to get good APIs. Two examples are Cisco Nexus and Juniper and both of these systems are ready to be used from Ansible.
Ansible with good old-fashioned Cisco IOS
A lot of us has quite a few Cisco IOS devices in production and most of them lack a modern API. If we want to use Ansible with them our three options are SSH, SNMP and https, where https often only gives us the same options as SSH.
As SSH is what most of us are used to it might make most sense to get Ansible to login this way. Perhaps using Netmiko. This basically means that we can replace the entire configuration or use screen scraping. While that works it leaves a lot to be desired.
Perhaps one of the best descriptions of SNMP is the one you used to see in the Nagios documentation; “As if designed to make the Gods of Hypocrisy die of laughter, SNMP is anything but simple.”
There are a lot of limitations with SNMP, while we have standard MIBs most of the interesting stuff is located in vendor specific MIBs. Even with the standard MIBs the implementation differs between vendors. While Cisco’s SNMP implementations are generally good it’s far from perfect. Some devices might have support for parts of a MIB. I wanted to write a Nagios plugin which would check the expiration date of certificates on Cisco routers. Sure enough Cisco has a MIB for this, but no devices to support it.
Anyway what’s good with SNMP is that you can check and change the state of specific settings. While most people probably poll their devices using SNMP, I would guess than only a small percentage change configuration using SNMP. If you want to do so SNMP version 3 is the way to go. It might be different, but it’s not hard to setup. A thing to keep in mind with SNMPv3 is that it’s very secure… compared to previous versions of SNMP. It provides encrypted logins and integrity. The problem with SNMP version 3 is that it doesn’t provide mutual authentication. Meaning the server, or network device in this case, doesn’t authenticate its identity to you. With SSH you have the host keys and with https you have certificates to let you know that the connection is to the correct machine. What this means to you is that you have to trust your routing infrastructure if you want to use SNMP version 3 to change device configurations. RFC 5592 mentions support for mutual authentication, and there are other options but I’ve never seen it in use.
Configuring Cisco IOS from Ansible with SNMP
Some months ago I developed an Ansible module which gathered facts from network devices using SNMP. Around the same time I was working with the lawful intercept functionality within some Cisco devices which uses SNMPv3 to set up taps, this made me grow more comfortable using snmpset. As I looked through the MIBs Cisco had I decided to write a few Ansible modules as a test. All of the code is available at GitHub with some instructions over at my blog.
As I’m writing this the available modules are:
- cisco_snmp_cdp – Enables or disables CDP globally or on an interface
- cisco_snmp_interface – Changes interface settings such as admin state and port description
- cisco_snmp_portsecurity – Enables/disable/configure port security
- cisco_snmp_save_config – Saves the running configuration to startup
- cisco_snmp_switchport – Change switchport mode access/trunk or access/native vlan for an interface
- cisco_snmp_vlan – Creates, deletes or renames VLANs
Changing configuration through SNMP only modifies the running-config, so when you use this in an Ansible Playbook you would notify the cisco_snmp_save_config module using the handlers functionality. An example could look like this:
An example playbook:
- hosts: all
- include: handlers/main.yml
- name: Create vlan 100 with SNMPv3
notify: save config
The handlers/main.yml file:
- name: save config
Running the above playbook would create VLAN 100 on the selected switches and give it the name SNMPV3VLAN. If the VLAN didn’t previously exist on a specific switch that would trigger the save_config module to be run.
These modules are geared toward switching, this is mostly since I was testing this concept against an 8-port Catalyst 2960 switch. It would be easy enough to add modules to configure layer 3 features. Though this is again depending on the fact that a MIB exists for each specific feature.
In the long run SNMP isn’t that optimal for network automation. But for now it works and these modules provides a way to work with your old Cisco devices from Ansible. Even if you don’t have any plans for allowing SNMP write access to your devices, I would urge you to give it a test in a small lab network. Set up a box running Ansible and do some testing with the modules. The way we manage network devices is changing and moving away from CLI. Tools like Ansible is some of those skills you will want in the future.