The Easiest Way to Build a Network Automation Lab | zeroslash.io

The Easiest Way to Build a Network Automation Lab

Submitted by zeroslash on Mon, 02/26/2018 - 13:59

For some time I have been trying different things on how to build a good Network Automation Lab. You would think that this can be as trivial as just your typical GNS3 lab hooked up with some VMs where you can launch your scripts, but in my mind, I wanted something very simple and straightforward, pretty much painless approach to building one. I had a good idea of how this kind of lab should be. Below are the points which guided me in my search for the right kind of setup.

  1. It should be easy enough for a beginner to follow step by step
  2. It should be simple and good enough to cover many different scenarios
  3. All software should be free and legitimately downloadable from the Internet
  4. The whole topology should be up and running with only a very few commands
  5. Only uses network devices with programmable interfaces

 

With all of these considered, I have come up with the below combination of software and tools for this lab.

 

That's it. This is really all you need. You will need to install both Virtualbox and Vagrant first. I won't be including the installation steps here. I will have to refer you to each of these software's installation procedures in their own websites. After the installation of these two then you can now proceed with the procedures below.

NOTE: All procedures below are for Linux or Mac OSX systems. If you are using Windows I'm sorry but I won't be covering that here.

Another thing I'd like to say is that I do acknowledge the fact that this will turn out to be a Juniper Network Automation Lab. But I'd like to point out that Juniper is not the focus nor is the reason for building this lab. It meets the requirements I had for this lab and using a single platform as of this stage would keep things simple for anyone who will use this procedure to get started. Getting started is much more important than trying to figure out how to cover multiple platform/vendor scenarios. I am open to expanding this in the future for another platform that offers features that Juniper does not, but in the meantime, Juniper does serve the purpose.

 

Step 1. Is to create a folder where we will do all your Vagrant work.

mkdir netautolab
cd ./netautolab     # change directory into it

 

Step 2. Install the Junos plugin

vagrant plugin install vagrant-junos

 

Step 3. Install the host-shell plugin.

vagrant plugin install vagrant-host-shell

 


 

Step 4. Create the vagrant file. This will define the devices and the topology we will use.

# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
  config.vm.box = "juniper/ffp-12.1X47-D15.4-packetmode"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = 1024
    vb.cpus = 2
    vb.gui = false
  end
  # vSRX1
  config.vm.define "vsrx1" do |vsrx1|
    vsrx1.vm.host_name = "vsrx1"
    vsrx1.vm.network "private_network",
                     ip: "10.99.12.1",
                     virtualbox__intnet: "1-2"
    vsrx1.vm.network "private_network",
                     ip: "10.99.13.1",
                     virtualbox__intnet: "1-3"
  end
  #vSRX2
  config.vm.define "vsrx2" do |vsrx2|
    vsrx2.vm.host_name = "vsrx2"
    vsrx2.vm.network "private_network",
                     ip: "10.99.23.2",
                     virtualbox__intnet: "2-3"
    vsrx2.vm.network "private_network",
                     ip: "10.99.12.2",
                     virtualbox__intnet: "1-2"
  end
  #vSRX3
  config.vm.define "vsrx3" do |vsrx3|
    vsrx3.vm.host_name = "vsrx3"
    vsrx3.vm.network "private_network",
                     ip: "10.99.13.3",
                     virtualbox__intnet: "1-3"
    vsrx3.vm.network "private_network",
                     ip: "10.99.23.3",
                     virtualbox__intnet: "2-3"
    vsrx3.vm.network "private_network",
                     ip: "192.168.56.12"
  end
  # server
  config.vm.define "netauto" do |server|
    server.vm.host_name = "netauto"
    server.vm.box = "centos/7"
    server.vm.network "private_network",
                       ip: "192.168.56.14"
  end
end

 

Step 5. Finally, let's bring the lab up and test the devices.

vagrant up     # It may take a couple of minutes to bring everything up

 

After the devices are up, verify the status.

vagrant status

 

It should have an output similar to below:

Current machine states:
vsrx1                     running (virtualbox)
vsrx2                     running (virtualbox)
vsrx3                     running (virtualbox)
netauto                   running (virtualbox)

 

Let's try to login on one of the vsrx devices

vagrant ssh vsrx1
--- JUNOS 12.1X47-D15.4 built 2014-11-12 02:13:59 UTC
root@vsrx1% cli
root@vsrx1> show version 
Hostname: vsrx1
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D15.4]
root@vsrx1> exit
root@vsrx1% exit
logout
Connection to 127.0.0.1 closed.

 

And that's it for setting up the lab part. What's left is to actually set up the tools we need to run some network automation. At the base of everything is of course to install Python. I have a post about Installing Python 3 for Development in Centos 7 Step by Step which nicely fits into this environment that we just created.

After installing Python 3 and setting up the development environment the only thing left to do is to test if we will be able to interact with our network devices. We will be using the official library for Juniper Junos called PyEZ.

 

Step 6. Installing PyEZ

I'm going to create a totally new virtualenv but if you wish to use an existing one feel free to do so.

[vagrant@netauto ~]$ python3 -m venv junos
[vagrant@netauto ~]$ cd ./junos
[vagrant@netauto junos]$ source ./bin/activate
(junos) [vagrant@netauto junos]$

 

Now install PyEZ

(junos) [vagrant@netauto junos]$ pip install junos-eznc
Collecting junos-eznc
  Using cached junos_eznc-2.1.7-py2.py3-none-any.whl
Collecting ncclient>=0.5.3 (from junos-eznc)
  Using cached ncclient-0.5.3.tar.gz
Collecting netaddr (from junos-eznc)
  Using cached netaddr-0.7.19-py2.py3-none-any.whl
Collecting six (from junos-eznc)
  Using cached six-1.11.0-py2.py3-none-any.whl
Collecting paramiko>=1.15.2 (from junos-eznc)
  Downloading paramiko-2.4.1-py2.py3-none-any.whl (194kB)
    100% |████████████████████████████████| 194kB 243kB/s 
<snip>
  Running setup.py install for pycparser ... done
  Running setup.py install for ncclient ... done
  Running setup.py install for MarkupSafe ... done
  Running setup.py install for PyYAML ... done
Successfully installed MarkupSafe-1.0 PyYAML-3.12 asn1crypto-0.24.0 bcrypt-3.1.4 cffi-1.11.5 cryptography-2.1.4 idna-2.6 jinja2-2.10 junos-eznc-2.1.7 lxml-4.1.1 ncclient-0.5.3 netaddr-0.7.19 paramiko-2.4.1 pyasn1-0.4.2 pycparser-2.18 pynacl-1.2.1 pyserial-3.4 scp-0.10.2 six-1.11.0

Now let's enable our devices to accept NETCONF.


 

Step 7. Configure NETCONF

This step is probably already configured by default but I'm including it here so you can do the same for any other new environment.

Log in to one of the VSRX. In this example I will configure VSRX3

vagrant ssh vsrx3

 

Then configure NETCONF over SSH.

root@vsrx3% cli
root@vsrx3> edit
Entering configuration mode
[edit]
root@vsrx3# set system services netconf ssh 
[edit]
root@vsrx3# commit
commit complete
[edit]
root@vsrx3# 

Note that we are still using SSH to access our devices so our connection is still secure. What we are doing here is we are tunneling NETCONF over SSH.

 

Step 8. Configure SSH key authentication

When we are performing these type of tasks such as automating configuration and sending commands, ideally we don't want to be typing in passwords. We want to be able to leave it to run on its own without requiring a human to enter a password. This is why we will use key-based authentication for our SSH sessions which our scripts will use. Also, we will be configuring this on a dedicated account for automation purposes. So our scripts will run as a certain user to implement accountability and will use a certain SSH key pair to increase security at the same time allowing us to run our scripts without human intervention (ie prompting for passwords).

NOTE: The SSH key-based authentication we will use here is very basic and is not recommended for production use. Ideally, it should be used with passphrases and SSH agents. However, this is not a post about SSH so I will keep it as simple as possible.

First, generate an SSH key pair (RSA key pair). We will not be using a passphrase as this is only for test/development.

[vagrant@netauto ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/vagrant/.ssh/id_rsa.
Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub.
<snip>
[vagrant@netauto ~]$ 

 

We will need to copy our public key (id_rsa.pub) and configure it on the VSRX.

[vagrant@netauto ~]$ cat /home/vagrant/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDnewB/WOUAf3Qkbgwa0LUb2JTI9W/WR1XFViZYNANECNBpIFCA0gY<snip>sQikkqnh8asu8D0w32aRlgRRjWpdACmL vagrant@netauto

 

Copy the long string starting from ssh-rsa to vagrant@netauto.

[edit]
root@vsrx3# set system login user netauto class super-user    
[edit]
root@vsrx3# set system login user netauto authentication ssh-rsa "<paste your public key here>"
[edit]
root@vsrx3# commit                                                            
commit complete

 

Now test if you can log in to VSRX3 by using just SSH keys.

[vagrant@netauto ~]$ ssh netauto@192.168.56.12
The authenticity of host '192.168.56.12 (192.168.56.12)' can't be established.
ED25519 key fingerprint is SHA256:+/uakdMKAEcpCkurKr2gRykHRlVK6AdWZFhZ75BKgdU.
ED25519 key fingerprint is MD5:43:03:25:15:c9:16:21:12:2c:a0:99:a5:68:2f:23:a3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.56.12' (ED25519) to the list of known hosts.

--- JUNOS 12.1X47-D15.4 built 2014-11-12 02:13:59 UTC

netauto@vsrx3> exit 
Connection to 192.168.56.12 closed.
[vagrant@netauto ~]$

We can confirm that we can log in. We can now proceed to write our test script to access and interact with our devices through code.


 

Step 9. Use PyEZ to send commands to our VSRX

Going back to our previously created virtualenv let's try out PyEZ from the Python interactive shell.

(junos) [vagrant@netauto junos]$ python
Python 3.6.4 (default, Feb 26 2018, 12:37:05) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from jnpr.junos import Device
>>> dev = Device(host='192.168.56.12', user='netauto')
>>> dev.open()
Device(192.168.56.12)
>>> print(dev.facts)
{'2RE': False, 'HOME': '/var/home/netauto', 'RE0': {'mastership_state': 'master', 'status': 'Testing', 'model': 'FIREFLY-PERIMETER RE', 'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'up_time': '1 hour, 28 minutes, 33 seconds'}, 'RE1': None, 'RE_hw_mi': False, 'current_re': ['master', 'node', 'fwdd', 'member', 'pfem', 'backup', 're0', 'fpc0.pic0'], 'domain': None, 'fqdn': 'vsrx3', 'hostname': 'vsrx3', 'hostname_info': {'re0': 'vsrx3'}, 'ifd_style': 'CLASSIC', 'junos_info': {'re0': {'text': '12.1X47-D15.4', 'object': junos.version_info(major=(12, 1), type=X, minor=(47, 'D', 15), build=4)}}, 'master': 'RE0', 'model': 'FIREFLY-PERIMETER', 'model_info': {'re0': 'FIREFLY-PERIMETER'}, 'personality': 'SRX_BRANCH', 're_info': {'default': {'0': {'mastership_state': 'master', 'status': 'Testing', 'model': 'FIREFLY-PERIMETER RE', 'last_reboot_reason': 'Router rebooted after a normal shutdown.'}, 'default': {'mastership_state': 'master', 'status': 'Testing', 'model': 'FIREFLY-PERIMETER RE', 'last_reboot_reason': 'Router rebooted after a normal shutdown.'}}}, 're_master': {'default': '0'}, 'serialnumber': '4672971cbd39', 'srx_cluster': False, 'srx_cluster_id': None, 'srx_cluster_redundancy_group': None, 'switch_style': 'BRIDGE_DOMAIN', 'vc_capable': False, 'vc_fabric': None, 'vc_master': None, 'vc_mode': None, 'version': '12.1X47-D15.4', 'version_RE0': '12.1X47-D15.4', 'version_RE1': None, 'version_info': junos.version_info(major=(12, 1), type=X, minor=(47, 'D', 15), build=4), 'virtual': True}
>>> dev.close()
>>> exit()
(junos) [vagrant@netauto junos]$

 

In the above code we opened a connection to our device (VSRX3) by instantiating a Device() object. We passed it 2 parameters, the host and user. As you would expect there was no need to pass a password parameter since we are using key-based authentication. We then printed out the "facts" which contains basic information about the device. Once done we closed the object and quit our Python shell.

Technically you can test our NETCONF connectivity using SSH and specifying the netconf subsystem like below.

[vagrant@netauto ~]$ ssh -s netauto@192.168.56.12 -p 830 netconf
<!-- No zombies were killed during the creation of this user interface -->
<!-- user netauto, class j-super-user -->
<hello>
  <capabilities>
    <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file</capability>
    <capability>http://xml.juniper.net/netconf/junos/1.0</capability>
    <capability>http://xml.juniper.net/dmi/system/1.0</capability>
  </capabilities>
  <session-id>1507</session-id>
</hello>
]]>]]>

 

The code example we did above was a more complete way to test it all together but testing it via SSH is a valid approach if you just want a quick connectivity test.

 

That's about it for our easiest way to build a network automation lab. This was longer than my usual posts, however, I believe that the details were necessary and I hope you were able to follow the steps with ease. I tried my best to make it as clear as possible. If you have any suggestions, comments or questions please do let me know by getting in touch through my contacts.