Categories
Networking Scripting

Procurve Secure Configuration Manager

This is a simple script that obtains the current running configuration of HP Procurve switches via SCP, compares it against previously stored versions, and stores any updated copy in the appropriate directory.  Once there are 10 copies the oldest copy is deleted automatically.  Again, I am using Pexpect for the SCP connection and authentication is handled via public key authentication.  To setup public key authentication on the switch, see my previous post.

#!/usr/bin/python
### The Procurve Public Key Automator Script needs to be run prior to utilizing this script ###

# Import modules needed for script
import pexpect
import sys
import time
import datetime
import os
import filecmp
import glob


# Change this to an appropriate directory that has read and write permissions for the user/group that will be running the script
path = '/var/sw_confs/'

# Create a dictionary to store all the devices and attributes
devices = {}

# Set Switches Attributes: make changes as necessary 
devices[('NYCoreSW-01')] =  '172.16.1.2'
devices[('ATLCoreSW-01')] = '172.16.2.2'
devices[('CHICoreSW-01')] = '172.16.3.2'
devices[('LACoreSW-01')] = '172.16.4.2'
devices[('SEACoreSW-01')] = '172.16.5.2'

# Create the base directory for storing the configs
if not os.path.exists(path):
  os.makedirs(path)
  
# Creates the individual directory for each switch
def sw_dir(host):
  conf_dir = path + host
  if not os.path.exists(conf_dir):
    os.makedirs(conf_dir)
  return conf_dir

# Builds the filename based on date and time for each switch config
def file_name():
  systime = time.time()
  timestamp = datetime.datetime.fromtimestamp(systime).strftime('%Y_%m_%d-%H_%M_%S')
  fn = ('%s.conf' % timestamp)
  return fn

# Loop through each switch	
for host in devices:
  conf_dir = sw_dir(host) + '/'
  os.chdir(conf_dir)
  rc = 'running-config.tmp'
  # Connect to the switch via scp and download the running config
  s = pexpect.spawn('scp %s:cfg/running-config %s' % (devices[host], rc))
  s.expect(pexpect.EOF, timeout=10)
  # Create a list of files ending in .conf and store them in order of creation date	
  conf_list = filter(os.path.isfile, glob.glob("*.conf"))
  conf_list.sort(key=lambda x: os.path.getmtime(x))
  # Check for existing conf files within the specific switch's directory and compare the last saved with the current running and if it's different save a new copy otherwise delete the copy (rc) just downloaded.
  if len(conf_list) >= 1:
    compare = filecmp.cmp(rc, conf_list[-1])
    if compare == False:
      fn = file_name()
      os.rename(rc, fn)
    elif compare == True:
      os.remove(rc)
  elif len(conf_list) < 1:
    fn = file_name()
    os.rename(rc, fn)
  # We are only interested in keeping the last 10 versions of config, so remove the oldest version.
  if len(conf_list) >= 9:
    os.remove(conf_list[0])

Once you have the script edited, modify permissions so that it is executable, and setup a cron job to run as often as you’d like to ensure all switches are backed up.  The example below backs up the configs every 30 minutes on the hour and half-hour mark.

crontab -e
0,30 * * * * /path/to/script/pscm.py
Categories
Networking Scripting

Automate HP Procurve Client Public-Key SSH Authentication Setup

This is a simple SSH public key management utility for HP Procurve switches that is a prerequisite to the automated backup script that is coming soon.  It first removes any existing keys, enables the TFTP client on the switch and then downloads and installs new public keys.  *Please be aware that there isn’t very much error handling built into this script.

On a Linux box, install and configure a TFTP server.  I using Debian in this scenario.

su root
apt-get update
apt-get install tftpd-hpa
vim /etc/default/tftpd-hpa

Make appropriate edits to the config file, restart the service and exit from root

service tftpd-hpa restart
exit

Generate an RSA key pair and copy the public key only to the TFTP server directory

ssh-keygen
cp /home/{username}/.ssh/id_rsa.pub  /srv/tftp/

If Pip and Pexpect isn’t installed yet:

wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
pip install pexpect

You can also create RSA key pairs in PuttyGen and add the public key ONLY to the TFTP server directory.

Edit the script below with TFTP server information, public key names, and devices.

# Import modules needed for script
import pexpect
import getpass
import sys

#TFTP server name, use either IP address or hostname if resolvable
tftphost = 'myTFTPserver.local'

#TFTP has no directory content listing function, so each public key's file name must be listed here.
managerkeys = ('my_key.pub', 'coworker_key.pub')
operatorkeys = ('backupserver_pub.key', 'auditserver_key.pub')

# Create a dictionary to store all the devices and attributes
devices = {}

# Set Switches Attributes and place them in the devices dictionary.
devices[('NYCoreSW-01')] = 'NYCoreSW-01', 'manager', '172.16.1.2', '.*\w+[\w\)]#'
devices[('ATLCoreSW-01')] = 'ATLCoreSW-01', 'manager', '172.16.2.2', '.*\w+[\w\)]#'
devices[('CHICoreSW-01')] = 'CHICoreSW-01', 'manager', '172.16.3.2', '.*\w+[\w\)]#'
devices[('LACoreSW-01')] = 'LACoreSW-01', 'manager', '172.16.4.2', '.*\w+[\w\)]#'
devices[('SEACoreSW-01')] = 'SEACoreSW-01', 'manager', '172.16.5.2', '.*\w+[\w\)]#'

### Definitions ###
  
# Open Switch connections
def switch_connect(d):
    #Setup the connection
    s = pexpect.spawn(('ssh %[email protected]%s' % (d[1], d[2])))
    #Expect 3 different results from the connection attempt
    login_result = s.expect(['.*Are you sure you want to continue connecting','.*assword: ','Press any key to continue'])
    #Add SSH Keys to known hosts file if this is the first time connecting. 
    if login_result == 0:
        s.sendline('yes')
    #Send password  
    elif login_result == 1:
        p = getpass.getpass('\nPlease enter the password for %s: ' % (d[0]))
        s.sendline(p)
    #If we already have keys installed on the switch then send a return key to bypass the MOTD  
    elif login_result == 2:
        s.send('\r')
    else:
        sys.exit()
    #Repeat passowrd entry until password is correct  
    login_result = s.expect(['Press any key to continue', '.*assword:', d[3]])
    while login_result == 1:
        p = getpass.getpass('\nPlease enter the correct password for %s: ' % (d[0]))
        s.sendline(p)
        login_result = s.expect(['Press any key to continue', '.*assword: '])						
    s.send('\r')
    s.expect(d[3])
    #Enable configuration mode
    s.sendline('conf')
    s.expect(d[3])
    return s;

# Close Switch connections
def switch_close(d,s):
    s.expect(d[3])
    #Save the config
    s.sendline('wr mem')
    s.expect(d[3])
    #Close the connection to the switch
    s.close()

### Add Keys by looping through devices###
  
for d in devices.values():
  s = switch_connect(d)
  #Revoke existing manager keys
  s.sendline('clear crypto client-public-key manager')
  s.expect('continue [y/n]?')
  s.sendline('y')
  s.expect(d[3])
  #Revoke existing operator keys
  s.sendline('clear crypto client-public-key operator')
  s.expect('continue [y/n]?')
  s.sendline('y')
  s.expect(d[3])
  #Keys can only be uploaded via TFTP, eliminate the next 2 lines if not using SCP for file transfers
  s.sendline('no ip ssh filetransfer')
  s.expect(d[3])
  #Allow public key authentication for SSH  
  s.sendline('aaa authentication ssh login public-key none')
  s.expect(d[3])
  #Enable TFTP client
  s.sendline('tftp client')
  s.expect(d[3])
  #Download manager keys from the TFTP server and install them
  for managerkey in managerkeys:
    s.sendline('copy tftp pub-key-file %s %s manager append' % (tftphost, managerkey))
    s.expect(d[3])
  #Download operator keys from the TFTP server and install them              
  for operatorkey in operatorkeys:
    s.sendline('copy tftp pub-key-file %s %s operator append' % (tftphost, operatorkey))
    s.expect(d[3])  
  s.sendline('ip ssh filetransfer')              
  switch_close(d,s)               
  #Let us know which switches have completed
  
  print ('%s complete.' % (d[0]))
print 'Script Complete'

To run the script:

python myscript.py
Categories
Networking Scripting

Python Scripting for HP Procurve Switches

I’ve working for the last several months on setting up a disaster recovery site, part of which required scripting network changes to streamline the process of making the site hot when necessary.  I wanted to connect from the scripting server to my networking devices via SSH for security purposes and I didn’t want to necessarily rely on using SSH keys.  For this task I chose to use Python 2.7 and Pexpect 3.3.  Initially I was hoping to use Pxssh which is included in Pexpect, but I was unsuccessful in getting being able to get Pxssh to work around issues with initial log-in messages and setting the command prompt.

I will create additional posts to supplement  this basic tutorial in the near future.

First, let’s make sure that the prerequisites are satisfied.

  1. You have a Linux machine of some variety available.
  2. You have Python 2.x installed.
  3. You have installed Pip, Pexpect and Netaddr
    wget https://bootstrap.pypa.io/get-pip.py
    python get-pip.py
    pip install pexpect
    pip install netaddr

Let’s build a simple test to verify connectivity

# Import modules needed for script
import pexpect
import getpass

# Setup Username, Hostname and Password
hostname = raw_input('hostname: ')
username = raw_input('username: ')
password = getpass.getpass('password: ')

# Spawn SSH session to the host
s = pexpect.spawn('ssh %[email protected]%s' % (username, hostname))

# Expect the switch to prompt for a password
s.expect('.*assword: ')

# Send the password
s.sendline(password)

# Expect the MOTD to end with 
s.expect('Press any key to continue')

# Send the return key
s.send('\r')

# Interact with the shell
s.interact()

Let’s drop:

# Interact with the shell
s.interact()

And add:

# Show the running configuration or substitute other commands
s.expect('.*\w+#') #Find the prompt
s.sendline('show running-config')

# Once the terminal window fills, we need to press the spacebar to continue printing the config
nextpage = s.expect(['--.*\w+l-C', '.*\w+#']) 
while nextpage == 0:
  # print everything before came before the continue message
  print s.before
  s.send(' ')
  nextpage = s.expect(['--.*\w+l-C', '.*\w+#'])
# Now we are out of the while loop so we need to print everything after that.
print s.after

In my next post, we’ll look at how to take the data gathered above and perform useful tasks with it.