Have you ever been in that situation that you needed to apply the same configuration quickly on multiple Cisco routers? If yes, you probably wrote a script that connected to routers and sent appropriate IOS commands. The one problem that you certainly had to solved was forcing your script to enter login credentials such as username and password. Moreover if you secured an access to privileged user mode with an enable secret command on your routers you had to tell the script how to enter that password as well.
All the issues I have mentioned above can be easily solved with Expect scripting language. Expect sends commands via telnet or ssh session as the human would. However encapsulating IOS commands to syntax recognized by Expect language every time you need to change routers' configuration seems to be not very comfortable. That is why public key authentication for Cisco routers can be handy.
Public key authentication allows you to log in to your routers using RSA key instead of a password. But firstly key-pair - public and private key must be generated and a public key copied into a config file of the router. Then you can connect to the router with your private key. A private key is the key that should be kept in secret and it is recommended to secure it with a password.
On Linux, ssh-keygen command can be used to generate RSA key-pair. The command below generates 4096 bit RSA key-pair without any user interaction and with a null password. Add the command in to your script if you want to automatize the process of generating your key-pair.
$ ssh-keygen -b 4096 -t rsa -f my_cisco_rsa -t rsa -N ''
-b number of bits in the key to create
-t type of the key
-f filename of the key file
Now we should have our RSA key-pair gecreated and we can start copying a content of the file my_cisco_rsa.pub that contains a public key into Cisco router configuration. But instead of copying an entire 4096 bits public key, Cisco offers an option to insert only a hash of your public key. This is definitely an advantage as copying a short hash string is less laborious than copying a whole public key. Anyway Cisco stores only a hash of the public key in its configuration even if you entered the entire public key.
So how can we find a hash of our public key? On Linux, enter the ssh-keygen command that we have used for generating the key-pair.
$ ssh-keygen -f my_cisco_rsa.pub -l
4096 5b:27:ba:1d:46:4c:32:1a:e5:b8:32:f9:4e:9e:bb:ae brezular@k55vm (RSA)
Obviously, our RSA public key is 4096 bits long and the hash of the key is: 5b:27:ba:1d:46:4c:32:1a:e5:b8:32:f9:4e:9e:bb:ae.
Add the hash to a router configuration as following.
cisco(config)# ip ssh pubkey-chain
cisco(conf-ssh-pubkey)# username admin
cisco(conf-ssh-pubkey-user)# key-hash ssh-rsa 5B27BA1D464C321AE5B832F94E9EBBAE
Assuming that your router contains configuration for ssh access to vty lines, you can now connect to the router using your private RSA key.
$ ssh -i my_cisco_rsa admin@ip_or_your_router
So far so good but you would probably like to automatize the process of deploying your public key on a remote Cisco router. Writing a script that can do this job for us is very likely a good idea, specially when you have many routers. In that case adding a key hash manually in to each router would be slow and not very efficient.
For this purpose I have written Bash script addkey.sh and Expect script addkey.tcl that work together and take care of deploying of your pub key on remote Cisco routers. The Bash script loops over IP addresses of your routers stored in a text file and send IP address as an argument to the Expect script together with login credentials. The Expect script establishes connection to a router using SSH and add a hash of your pub key into to a config file of the router. It also creates a new privilege user with privilege level 15. We will use this user to jump directly to a privileged user mode after the login to a router.
Parameters of the script are displayed below. You have to enter all the script parameters except of the last -h parameter.
Picture 1 - Bash Script Parameters
Testing Script on Cisco Routers
I have created a lab topology in GNS3 that consists of three routers running BGP protocol. The routers are Cisco 7206VXR emulated by Dynamips an running IOS C7200-ADVENTERPRISEK9-M, version 15.2(4)S2.
Picture 2 - GNS3 Lab Topology
In order to achieve a full bi-directional connectivity between lab routers and my Linux box I have done following.
I have created a tap interface tap0 and bridged it to the physical Ethernet interface p3p1 that connects my computer to my LAN home network. I have assigned an IP address 172.16.100.6/16 from the LAN subnet to a bridge interface br0 and created a static route pointing packets to the subnet 10.10.10.0/28 via IP address 172.16.100.200. This IP address is configured on interface fa3/0 of the router R3. Here are the appropriate commands of the iproute2 utility that I have used.
I have created a cloud (server symbol in a topology) and added the interface tap0 interface to the cloud configuration. Now we can run our script with the command.
$ ./addkey.sh -f iplist -g addkey.tcl -i my_cisco_rsa.pub -u student -p ucebna -s ucebna -x admin -z cisco
-f path to file that contains list of the IP addresses of routers
-g path to Expect script
-i path to file that contains private RSA key
-u name of unprivileged (level 0) user that script is going to use to connect to router
-p password for unprivileged (level 0) user
-s password for access to enable mode of router
-x name of privileged user (level 15) who is going to be created by script
-z password for privileged (level 15) user
At this point we should have our routers configured for public key authentication. To test if it is working we are going to send several Cisco IOS command to the router R1. We will place the commands in to a text file commands-r1.txt and redirect a content of the file to the router over ssh session. The commands configure banner, public Google DNS server and BGP protocol authentication with the BGP peer R2 on the router R1.
$ ssh -i my_cisco_rsa firstname.lastname@example.org < commands-r1.txt
And we will do the same for a router R2 but with a file commands-r2.txt instead.
$ ssh -i my_cisco_rsa email@example.com < commands-r2.txt