Home

Awesome

Cisco Switchport Auditor

Table of Contents

Project Summary

Parses Cisco switch configuration into Switch & Interface objects to access configuration details of the aforementioned in a programatic manner. Works with SSH, RESTCONF, or with running/start-up config files.

Motivation for this tool

I wanted to develop a tool to review Cisco switchport/interface configurations in a programable way. I found I was making a lot of custom scripts and wanted something that made the data obtained easy to work with and was scalable. Network programability is also a strong interest of mine. I hope someone else will be able to find use out of it as I have. <br /> <br />

How it works

Obtaining the data

Parsing the data

Once the data has been obtained, it must be parsed to be stored and used programmatically.

For textual outputs of the configuraiton that have been obtained over SSH or via a configuration file, I utilitized a project called CiscoConfParse. Essentially, what this does is use regex logic to find relevant configuration information.

For output returned via RESTCONF -- JSON is returned so that can be iterated and parsed by using python dictionaries.

The parsers can be found in the /parsers directory. The parsers are responsibile for obtaining and then assigning the parsed data to models which will be explained in the following section.

Structuring/Managing Parsed Data

There are two classes (Switch & Interface) in the /models directory. All configuration details (e.g. interface names, VLAN ids, hostnames, etc) that are parsed are added to these objects as attributes so they can be iterated through and reviewed/audited. Interface objects are found within each Switch object inside a list attribute. Greater explanation (with examples) is shown in the Using Switch & Interface Objects section.

Installation

  1. Git clone this project and change your working directory to its downloaded location
  2. Execute in terminal pip install -r requirements.txt

Usage

Navidate to the cisco_switchport_auditor/cisco_switchport_auditor directory

Generating switch objects from running-configs:

<br />

1. SSH into a switch to obtain its running-config

from master_functions import parse_from_SSH_output

hosts = ['10.0.0.1', '10.0.0.2']

switches = parse_from_SSH_output(hosts, save_to_excel=False)
<br />

2. Importing a directory of configuration files

from master_functions import parse_from_config_file

config_files = '/home/myuser/configs'

switches = parse_from_config_file(config_files, save_to_excel=False)
<br />

3. Using RESTCONF to obtain data

from master_functions import parse_from_restconf

hosts = ['10.0.0.1', '10.0.0.2']

switches = parse_from_restconf(hosts, save_to_excel=False)

Using Switch & Interface Objects

Once a list of switch objects have been instantiated and the configuration parsed, you can use the switch (and attached interface objects) to evaluate object attributes for auditing purposes. Two examples have been provided below.

I have personally used this tool to audit a network that was comprised of roughly 25,000 access ports. Evaluating network configuration in an automated and programmatic way is very scalable, less prone to human-error, and can be executed on demand if configured as a service on a schedule or callable by some type of API. Essentially, your ability to be creative is your limitation.

The information obtained with this tool can be used in a variety of ways. A couple of examples are to write the information to a database, an excel file or send notifications.

As a final note, there isn't parity in the model/object attributes obtained via the various methods/parsers (i.e. SSH, restconf). What is available for each method is tracked in the table below. Support may eventually be added in the future to add more attributes or achieve greater parity

<br />

Switch Objects Attributes

AttributeTypeDescriptionExampleSSH SupportConfig File SupportRESTCONF Support
configstrSwitch's running-configN/A:heavy_check_mark::heavy_check_mark::x:
config_filenamestrSwitch's config file namemyswitch.conf:x::heavy_check_mark::x:
config_restconfdictSwitch's running-config as JSONN/A:x::x::heavy_check_mark:
hostnamestrThe Switch's hostnameMY_SWITCH:heavy_check_mark::heavy_check_mark::heavy_check_mark:
interfaceslistA list of interface objectsN/A:heavy_check_mark::heavy_check_mark::heavy_check_mark:
ip_address (optional)strSwitch's management IP10.0.0.1:heavy_check_mark::x::heavy_check_mark:
vlanslistA list of named tuples that contains <br> the VLAN name and VLAN ID[vlan(id=300, name='Test_VLAN_300'), <br> vlan(id=400, name='Test_VLAN_400'):heavy_check_mark::heavy_check_mark::heavy_check_mark:

Interface Object Attributes:

AttributeTypeDescriptionExampleSSH SupportConfig File SupportRESTCONF Support
admin_downboolReturns True if admin shutdownTrue OR False:heavy_check_mark::heavy_check_mark::heavy_check_mark:
configstrInterface specific running config...<br> description Test Description <br> switchport access vlan 10 <br> switchport mode access <br> switchport port-security <br> ...:heavy_check_mark::heavy_check_mark::x:
config_restconfdictInterface's running-config as JSONN/A:x::x::heavy_check_mark:
descriptionstrInterface's descriptionTest Description:heavy_check_mark::heavy_check_mark::heavy_check_mark:
IPDT_policystrAssigned IPDT policyIPDT_MAX_10:heavy_check_mark::heavy_check_mark::heavy_check_mark:
is_access_portboolReturns True if access PortTrue OR False:heavy_check_mark::heavy_check_mark::heavy_check_mark:
is_trunk_portboolReturns True if trunk PortTrue OR False:x::x::heavy_check_mark:
ise_compliantboolMatches a subset of commands <br> see the method for more detailsTrue OR False:heavy_check_mark::heavy_check_mark::x:
namestrThe interface's nameGigabitEthernet2/0/1:heavy_check_mark::heavy_check_mark::heavy_check_mark:
switch_hostnamestrThe Switch's hostnameMY_SWITCH:heavy_check_mark::heavy_check_mark::heavy_check_mark:
switch_vlanslistA list of named tuples that contains <br> the VLAN name and VLAN ID[vlan(id=300, name='Test_VLAN_300'), <br> vlan(id=400, name='Test_VLAN_400')]:heavy_check_mark::heavy_check_mark::heavy_check_mark:
typestrInterface media typeGigabitEthernet:heavy_check_mark::heavy_check_mark::heavy_check_mark:
vlanintVLAN ID of the interface345:heavy_check_mark::heavy_check_mark::heavy_check_mark:
vlan_namestrVLAN name of the interfaceTEST_VLAN:heavy_check_mark::heavy_check_mark::heavy_check_mark:
voice_vlanintVoice VLAN ID250:heavy_check_mark::heavy_check_mark::heavy_check_mark:
voice_vlan_namestrVoice VLAN nameTEST_VOICE_VLAN:heavy_check_mark::heavy_check_mark::heavy_check_mark:

Find switchports that are access ports without NAC (network access control) configuration

for switch in switches:
    for interface in switch.interfaces:
        if interface.is_access_port == True and interface.ise_compliant != True:
             # Write to database
             # Write to excel file
             # Send notification to network team
             # Your cool idea here!

Find switchports that do not have an interface description and are access ports and in VLAN 350

for switch in switches:
    for interface in switch.interfaces:
        if not interface.description and interface.is_access_port == True and interface.vlan == 350:
             # Write to database
             # Write to excel file
             # Send notification to network team
             # Your cool idea here!

Find which switches have VLAN 948 configured

for switch in switches:
    for vlan in switch.vlans:
        if vlan.id == 948:
             # Write to database
             # Write to excel file
             # Send notification to network team
             # Your cool idea here!

Exporting to Excel

I've added in functionality to the main functions mentioned at the beginning of the usage section. Setting the arg save_to_excel to True will generate an excel file in the directory the program is run in. 1 excel file will be created with a new excel worksheet created for each switch (named after the switch's hostname). Inside each worksheet will be entries for each interface found on the switch referenced in the worksheet name.

Modifying the project for your specific usage

I've endeavoured to write this project in a way where adding new configuration checks can be done easily for myself in the future. I've documented the process so when I come back in 6 months I won't forget. Hopefully others can benefit from this as well! :) After following the instructions below you can use your new object attribute in the same manner described in the usage section of this document. As this project is focused on interface configuration/details, I have only included instructions on how to modify interface-related details. Below are instructions to modify both the regex (SSH & file-based textual conf) and RESTCONF parsers.

As a further note, I am using the pydantic project that allows you to define what the type value is for the attributes you are adding. This also enforces that no extra attributes are added or no attributes can be updated with incorrect type definitions. See the Interface class in /models/interface.py for examples. Keep this in mind when creating new object attributes referenced in the instructions below.

Modifying to obtain new interface configuration details - regex/text based output


Interface configuration value check

<br />

Extract a specific value from a line of configuration. In example, say we wanted to obtain 300 from switchport access vlan 300.

<br />

Check if configuration line/command is present in interface config

<br />

Checks if a line of configuration is present in the interface specific running-config. An example of this is if the interface is administraively shutdown. Will return True if there is a match and False if there is no match...

<br />

Check if a subset of configuration lines/commands are present in the interface config

<br />

Similar to here, but checks if an entire command/configuration subset is in the interface configuration.

Example, if you wanted to see if a switchport had ALL the AAA/ISE configuration commands present in it for switchport security compliance, this functionality would check this. If all the ISE/AAA switchport commands are present in the interface specific running configuration, the result of True will be returned but if ANY are missing a result of False will be returned

Modifying to obtain new interface configuration details - RESTCONF

SSH considerations

Potential Improvements

Credits

Thanks to mpenning and all the contributers from the ciscoconfparse project!