Sunday, November 6, 2016

Auditing Cisco Switches with python, paramiko and SSH part 1



Auditing Cisco Switches with python, paramiko and SSH
When your datacenters and HCI offerings are top cakes in the market it can’t just happen by doing it right but also by making sure you have done it right. In VCE (now EMC DELL HCI) we have at the least 9+ quality checks before the client gets it and more onsite once we do the plug and play of the datacenter. Powershell is and was a great thing to achieve some of these but powershell doesn’t have native ssh support and you might get away with plink or other custom ssh modules but then again it is not as snappy and as convenient as python with paramiko module. Python is great at configuring stuff, validating, auditing and for many other things due to its compatibility. Powershell is now stepping into linux but python is still a bit way ahead of powershell when it comes to practicality and usability. I find powershell to be easy to use due to it’s very small learning curve and how easy it is to read or write code but python nonetheless is the top dog for now so you go with what works the most, most of the times and at most of the places.
In my previous post we explored how to do http://ambitech.blogspot.in/2016/11/paramiko-and-ssh-via-python-2x.html ssh to targets on windows via python through paramiko module. Please refer that because without that it might not make much sense. Now let us take it further by trying to get the output saved to some text file.

target   = ‘1.1.1.1’
username = ‘admin’
password = ‘@dmin’

filename = target +'.commands.txt' #name of the file with commands and their output
The above defines the details of the cisco switch, for which we want to pull the report.

Now let us create an array of commands that we want to run against the switches. Below is a sample

    commands = [ #Here we will list out all the commands that we have to run in a cisco switch
    "show feature                      ",
    "show banner motd                  ",
    "show run | inc route              ",
    "show int desc                     ",
    "show license usage                ",
    "show version                      ",
    "show inventory                    ",
    "show vpc brief                    ",
    "show hsrp brief                   ",
    "show environment                  ",
    "show port-channel summary         ",
    "show vlan                         ",
    "show module                       ",
    "show redundancy status            ",
    "show int counters errors          ",
    "show int brief                    ",
    "show int status                   ",
    ]

Below is a method to get the complete filename
import inspect, os, sys

def get_script_dir(follow_symlinks=True):
    if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
        path = os.path.abspath(sys.executable)
    else:
        path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        path = os.path.realpath(path)
    return os.path.dirname(path)

scriptpath = get_script_dir() #path where the script resides
filepath = "%s\%s" % (scriptpath, filename) #full path to the filename including the file itself
#print filepath

Thanks to stackoverflow, the custom function get_script_dir is going to act as an equivalent of $psscriptroot in powershell. If you run the whole thing with #print filepath uncommented then you will know that it will print out the exact path to the root directory from which you are running the script from. Now let us append the filename to this path to get the full path to the filename and the filename itself so that it would be easy for us to create a file to which we are going to append the outputs of the cisco switch.

Below should be self-explanatory

    import paramiko #import paramiko module
    ssh  = paramiko.SSHClient() #create an ssh client
   
    open(filepath, 'w') #create file
    with open(filepath,"a") as myfile:
        for command in commands:
            print command
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #auto accept ssh key
            ssh.connect(target, port=22, username=username, password=password) #connect to the target
            stdin, stdout, stderr = ssh.exec_command(command) #execute the command
            output = stdout.readlines() #get the output
            outstore = '\n'.join(output) #format the output to print each line in a new line
            print outstore #print outstore
            file = myfile.write
            file('\n start of ' + command) #append the name of the command for which we have the ouput
            file('\n=====================================')
            file('\n')
            file(outstore) #actual command’s output
            file('\n')
            file('\n end of ' + command)
            file('\n-------------------------------------')

So now when you run this script it will generate a text output named
Target.commands.text (where target is the address of the switch) with the data which looks like this

start of show banner motd                 
=====================================


***W A R N I N G***

THIS IS A VERY PRIVATE  SYSTEM.

This  system including all related equipment, network devices,

are provided only for authorized use.

All  systems will be monitored for all lawful purposes, including

those activities that are authorized for management of the system.

All information including personal information, stored or sent over this

system will be monitored.

Uses of this system, authorized or unauthorized, constitutes consent to

monitoring of this system.

Unauthorized use will subject you to criminal prosecution.

WARNING: Unauthorized access to this system is forbidden and will be

prosecuted by law.

By accessing this system, you agree that your actions will be monitored and batman is the best superhero out there and the entire marvel universe is just the imagination of franklin richards.


 end of show banner motd                 
-------------------------------------
 start of show run | inc route             
=====================================
ip route 0.0.0.0/0 192.188.11.11

no ip source-route


 end of show run | inc route             
-------------------------------------
 start of show int desc                    
=====================================

Go get this here