If you have been following along with the posts so far, you will know that we are using Vagrant to help automate the provision of VNFs within VirtualBox.
Vagrant uses “Box” files as a template to spin up multiple copies of a Virtual Machine (VM). To re-use this Cisco CSR 1000V VM, we need to convert it into a re-usable Box image.
Box files have a few requirements that should be applied to the VM to operate correctly. These are:
- The first interface (management) is set to get its address from DHCP.
- There is a user called vagrant configured with a password of “vagrant”.
- Vagrant must be able to SSH to the VM.
- There is a default SSH key applied to the “vagrant” user.
So, let’s configure these settings on our newly created IOS image. We’ll start with DHCP. Enter the commands below in the CLI:
Router>enable
Router#configure terminal
Router(config)#interface gigabitEthernet 1
Router(config-if)#ip address dhcp
Router(config-if)#end
Router#show ip int br
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.56.106 YES DHCP up up
Router#write memory
Building configuration...
[OK]
Now that we have DHCP configured on our GigabitEthernet1 interface, let’s set up the “vagrant” user and SSH.
Router#configure terminal
Router(config)#username vagrant privilege 15 secret vagrant
Router(config)#aaa new-model
Router(config)#aaa authentication login default local
Router(config)#aaa authorization exec default local
Router(config)#hostname ios
ios(config)#ip domain name nfv.dev
ios(config)#crypto key generate rsa modulus 2048
% You already have RSA keys defined named ios.nfv.dev.
% They will be replaced.
% The key modulus size is 2048 bits
% Generating 2048 bit RSA keys, keys will be non-exportable...
[OK] (elapsed time was 0 seconds)
ios(config)#ip ssh version 2
ios(config)#ip scp server enable
ios(config)#end
ios#write memory
Open up a WSL2 terminal (either in Windows Terminal, VSCode or by searching “Ubuntu” in the start menu”) and try SSHing to the CSR VM (if asked to trust the host, type “yes”):
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ ssh vagrant@192.168.56.106
The authenticity of host '192.168.56.106 (192.168.56.106)' can't be established.
RSA key fingerprint is SHA256:27mVVH1Tt9UBOM1EXwVbkNGDXXtMFxD30DxINurfZ6Q.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.56.106' (RSA) to the list of known hosts.
Password:
ios#
Finally, we should add the Vagrant default SSH key into the vagrant user to log in without using a password. The Vagrant default SSH key can be found at https://github.com/hashicorp/vagrant/blob/master/keys/vagrant.pub.
Note: This is very insecure and should not be used in a production environment.
ios#configure terminal
ios(config)#ip ssh pubkey-chain
ios(conf-ssh-pubkey)#username vagrant
ios(conf-ssh-pubkey-user)#key-string
ios(conf-ssh-pubkey-data)#AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9e
ios(conf-ssh-pubkey-data)#WW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS
ios(conf-ssh-pubkey-data)#0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBck
ios(conf-ssh-pubkey-data)#FXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUec
ios(conf-ssh-pubkey-data)#p4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd
ios(conf-ssh-pubkey-data)#0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96
ios(conf-ssh-pubkey-data)#hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ==
ios(conf-ssh-pubkey-data)#exit
ios(conf-ssh-pubkey-user)#end
ios#write memory
Great, that should be it. Let’s test it out.
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ ssh -i .vagrant.d/insecure_private_key vagrant@192.168.56.106
ios#
Awesome, we logged into the Cisco CSR without a password using the Vagrant insure private key.
Before creating our Box file, we need to do one more thing. We statically set the serial port on the VM to be “\\.\pipe\csr”. If we want to create multiple VMs, we need a different name for each VM’s serial port. We could develop a fancy way of doing this; however, we do not need the serial port as we have SSH working now.
Power down the VM. Go into the VM’s Settings and then “Serial Ports”. Then change “Port 1”, “Port Mode” to “Disconnected”.
Ok, now it’s time to package everything up into a reusable Box file. From within Linux, run “vagrant package –base <name_of_vm> –output <name_of_output_file>.box”:
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ export VAGRANT_HOME="/mnt/c/Users/nfvdev/.vagrant.d"
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ vagrant package --base csr1000v-universalk9.17.03.02-serial --output csr1000v-universalk9.17.03.02-serial.box
==> csr1000v-universalk9.17.03.02-serial: Exporting VM...
==> csr1000v-universalk9.17.03.02-serial: Compressing package to: /mnt/c/Users/nfvdev/csr1000v-universalk9.17.03.02-serial.box
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ export VAGRANT_HOME="~/.vagrant.d"
This creates a file called csr1000v-universalk9.17.03.02-serial.box for us to reuse. We can then test the box image by creating a Vagrantfile with the following contents. The entire file available at: https://github.com/nfvdev/nfvdev-blog/blob/main/05-how-to-create-a-cisco-csr-1000v-box-image/single/Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.ssh.insert_key = false # By default, Vagrant will try and change the insecure SSH key to a better one. This won't work for us as it does not know how to talk ios.
config.vm.box = "csr1000v-universalk9.17.03.02-serial.box" # Use the ios box image
config.vm.synced_folder '.', '/vagrant', disabled: true # Disable shared folders
config.vm.guest = :linux # Tell Vagrant that it is Linux so it doesn't error
end
And then type “vagrant up” to spin up the VM.
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'csr1000v-universalk9.17.03.02-serial.box'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: nfvdev_default_1642936280913_64423
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 172.25.64.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
default: No guest additions were detected on the base box for this VM! Guest
default: additions are required for forwarded ports, shared folders, host only
default: networking, and more. If SSH fails on this machine, please install
default: the guest additions and repackage the box to continue.
default:
default: This is not an error message; everything may continue to work properly,
default: in which case you may ignore this message.
Finally, we can check that Vagrant can SSH into the newly created IOS VM:
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ vagrant ssh default
ios#exit
Connection to 172.25.64.1 closed.
We can destroy the VM with “vagrant destroy” and remove our template VM.
nfvdev@ubuntu:/mnt/c/Users/nfvdev$ vagrant destroy
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
IOS Vagrant Mini-Lab
Now that we have our IOS Box file created, we can use it in a mini-lab. This will set up 2 IOS routers connected back to back and do some ping tests between them.
- In an empty folder, create a Vagrantfile with the contents from https://github.com/nfvdev/nfvdev-blog/blob/main/05-how-to-create-a-cisco-csr-1000v-box-image/minilab/Vagrantfile
- Spin up the VMs with “vagrant up”
- SSH to ios1 with “vagrant ssh ios1” and configure it with the commands from https://github.com/nfvdev/nfvdev-blog/blob/main/05-how-to-create-a-cisco-csr-1000v-box-image/minilab/ios1.cfg
- SSH to ios2 with “vagrant ssh ios2” and configure it with the commands from https://github.com/nfvdev/nfvdev-blog/blob/main/05-how-to-create-a-cisco-csr-1000v-box-image/minilab/ios2.cfg
- From ios2 check connectivity with “ping 10.100.1.1 interface 10.100.2.2” and “show ip ospf neighbor”
- Destroy the lab with “vagrant destroy -f”
nfvdev@ubuntu:/mnt/c/Users/nfvdev/boxes$ vagrant up
Bringing machine 'ios1' up with 'virtualbox' provider...
Bringing machine 'ios2' up with 'virtualbox' provider...
==> ios1: Box 'csr1000v-universalk9.17.03.02-serial.box' could not be found. Attempting to find and install...
ios1: Box Provider: virtualbox
ios1: Box Version: >= 0
==> ios1: Box file was not detected as metadata. Adding it directly...
==> ios1: Adding box 'csr1000v-universalk9.17.03.02-serial.box' (v0) for provider: virtualbox
ios1: Unpacking necessary files from: file:///mnt/c/Users/nfvdev/boxes/csr1000v-universalk9.17.03.02-serial.box
==> ios1: Successfully added box 'csr1000v-universalk9.17.03.02-serial.box' (v0) for 'virtualbox'!
==> ios1: Importing base box 'csr1000v-universalk9.17.03.02-serial.box'...
==> ios1: Matching MAC address for NAT networking...
==> ios1: Setting the name of the VM: boxes_ios1_1642937334161_8769
==> ios1: Clearing any previously set network interfaces...
==> ios1: Preparing network interfaces based on configuration...
ios1: Adapter 1: nat
ios1: Adapter 2: intnet
ios1: Adapter 3: intnet
==> ios1: Forwarding ports...
ios1: 22 (guest) => 2222 (host) (adapter 1)
ios1: 22 (guest) => 2222 (host) (adapter 1)
==> ios1: Booting VM...
==> ios1: Waiting for machine to boot. This may take a few minutes...
ios1: SSH address: 172.25.64.1:2222
ios1: SSH username: vagrant
ios1: SSH auth method: private key
==> ios1: Machine booted and ready!
==> ios1: Checking for guest additions in VM...
ios1: No guest additions were detected on the base box for this VM! Guest
ios1: additions are required for forwarded ports, shared folders, host only
ios1: networking, and more. If SSH fails on this machine, please install
ios1: the guest additions and repackage the box to continue.
ios1:
ios1: This is not an error message; everything may continue to work properly,
ios1: in which case you may ignore this message.
==> ios2: Box 'csr1000v-universalk9.17.03.02-serial.box' could not be found. Attempting to find and install...
ios2: Box Provider: virtualbox
ios2: Box Version: >= 0
==> ios2: Box file was not detected as metadata. Adding it directly...
==> ios2: Adding box 'csr1000v-universalk9.17.03.02-serial.box' (v0) for provider: virtualbox
==> ios2: Importing base box 'csr1000v-universalk9.17.03.02-serial.box'...
==> ios2: Matching MAC address for NAT networking...
==> ios2: Setting the name of the VM: boxes_ios2_1642937512209_62343
==> ios2: Fixed port collision for 22 => 2222. Now on port 2200.
==> ios2: Clearing any previously set network interfaces...
==> ios2: Preparing network interfaces based on configuration...
ios2: Adapter 1: nat
ios2: Adapter 2: intnet
ios2: Adapter 3: intnet
==> ios2: Forwarding ports...
ios2: 22 (guest) => 2200 (host) (adapter 1)
ios2: 22 (guest) => 2200 (host) (adapter 1)
==> ios2: Booting VM...
==> ios2: Waiting for machine to boot. This may take a few minutes...
ios2: SSH address: 172.25.64.1:2200
ios2: SSH username: vagrant
ios2: SSH auth method: private key
==> ios2: Machine booted and ready!
==> ios2: Checking for guest additions in VM...
ios2: No guest additions were detected on the base box for this VM! Guest
ios2: additions are required for forwarded ports, shared folders, host only
ios2: networking, and more. If SSH fails on this machine, please install
ios2: the guest additions and repackage the box to continue.
ios2:
ios2: This is not an error message; everything may continue to work properly,
ios2: in which case you may ignore this message.
nfvdev@ubuntu:/mnt/c/Users/nfvdev/boxes$ vagrant ssh ios1
ios#configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
ios(config)# hostname ios1
ios1(config)# interface GigabitEthernet 2
ios1(config-if)# ip address 10.100.12.1 255.255.255.0
ios1(config-if)# description External
ios1(config-if)# no shutdown
ios1(config-if)# interface GigabitEthernet 3
ios1(config-if)# ip address 10.100.1.1 255.255.255.0
ios1(config-if)# description Internal
ios1(config-if)# no shutdown
ios1(config-if)# router ospf 1
ios1(config-router)# router-id 10.100.12.1
ios1(config-router)# passive-interface GigabitEthernet 3
ios1(config-router)# network 10.100.12.0 0.0.0.255 area 0.0.0.0
ios1(config-router)# network 10.100.1.0 0.0.0.255 area 1.1.1.1
ios1(config-router)# end
ios1#write memory
Building configuration...
[OK]
ios1#exit
Connection to 172.25.64.1 closed.
nfvdev@ubuntu:/mnt/c/Users/nfvdev/boxes$ vagrant ssh ios2
ios#configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
ios(config)# hostname ios2
ios2(config)# interface GigabitEthernet 2
ios2(config-if)# ip address 10.100.12.2 255.255.255.0
ios2(config-if)# description External
ios2(config-if)# no shutdown
ios2(config-if)# interface GigabitEthernet 3
ios2(config-if)# ip address 10.100.2.2 255.255.255.0
ios2(config-if)# description Internal
ios2(config-if)# no shutdown
ios2(config-if)# router ospf 1
ios2(config-router)# router-id 10.100.12.2
ios2(config-router)# passive-interface GigabitEthernet 3
ios2(config-router)# network 10.100.12.0 0.0.0.255 area 0.0.0.0
ios2(config-router)# network 10.100.2.0 0.0.0.255 area 2.2.2.2
ios2(config-router)# end
ios2#write memory
Building configuration...
[OK]
ios2#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
10.100.12.1 1 FULL/BDR 00:00:35 10.100.12.1 GigabitEthernet2
ios2#ping 10.100.1.1 source 10.100.2.2
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 10.100.1.1, timeout is 2 seconds:
Packet sent with a source address of 10.100.2.2
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms
ios2#exit
Connection to 172.25.64.1 closed.
nfvdev@ubuntu:/mnt/c/Users/nfvdev/boxes$ vagrant destroy -f
==> ios2: Forcing shutdown of VM...
==> ios2: Destroying VM and associated drives...
==> ios1: Forcing shutdown of VM...
==> ios1: Destroying VM and associated drives...