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.