10. Virtualization with KVM


The goal of virtualization is to provide a software platform consisting an instance of an operating system running as a virtual machine within the existing machine. A system which supports virtualization is called the host and a virtual machine is called a guest. There are a number of software tools called hypervisors, which serve as the virtualization software, including KVM, XEN, VmWare, VirtualBox, etc. Ubuntu focuses on the KVM (Kernel-based Virtual Machine) software which requires that the CPU has a hardware virtualization extension.

The main benefit for us is the ability to set up a "test bed" for trying out software and networking features without using other physical computers. One can use this virtualization to install multiple versions of Linux in order to evaluate and compare them. From a security perspective, we can use virtual machines as "attack targets" for security software testing. In an enterprise setting a virtual machine can be a lightweight specialized "server" which is optimized to perform one service task.

Enable Virtualization in the BIOS

This is how to do so for the Lab computers. Start by rebooting the machine. You have to catch it before it boots the operating system. Type F12 repeatedly as we did for the installation.
  1. Select: Enter Setup
  2. Go to the Advanced tab, select CPU Setup.
  3. Select Intel (R) Virtualization Technology [Disabled]. Enter
  4. Select Enabled. Enter.
  5. Type F10 to save and exit.

Software Installation

Install the necessary packages:
$ sudo apt install qemu qemu-kvm virt-manager virt-viewer \
                   libvirt-bin uvtool uvtool-libvirt
As installer, you are added to the libvirtd group allowing you to use the virtualization tools as you without becoming root. You must log-out/log-in in order to pick up your membership in this group.

After logging in again, confirm:
$ groups
... libvirt ...
Our guest machine's network will be attached to the virtual bridge interface virbr0, which has been created in the libvirt-bin installation. Check it out by:
$ ifconfig virbr0

Get Cloud Images

We're going to use so-called cloud images obtained and manipulated by the uvtool package.
Download the cloud image (this takes some time, be patient). The current release (bionic) has some bugs which make it impossible to do everything we want to do, so we're using the 17.10 version, xenial:
$ uvt-simplestreams-libvirt sync release=xenial arch=amd64

Create a VM and access it

In order to be able to get into the virtual machines created from the cloud image, you need to have created your RSA key:
Then create the machine and start it running:
[MACHINE]$ uvt-kvm create vm release=xenial --memory 256
Within a short time, you can access it by:
[MACHINE]$ uvt-kvm ssh vm --insecure
Your login is ubuntu. The VM creation aleady establishes key access to the guest using this login which you can check by:
ubuntu@vm:~$ cat .ssh/authorized_keys
In fact, by default, the only way you can externally access this VM is by public key. You can check that out by:
ubuntu@vm:~$ egrep ^.?Password /etc/ssh/sshd_config
PasswordAuthentication no
whereas if you go back to the host and do the same, you'll see
[MACHINE]$ egrep ^.?Password /etc/ssh/sshd_config
#PasswordAuthentication no
The significance is the password authentication is intentionally turned off in the guest machines created in this way.

RAM and Disk space

The "--memory 256" flag means give the VM 256M of RAM, which is subtracted from RAM available to the host when the guest is running. According to the Ubuntu docs, 192M of RAM is sufficient to run the server OS.

The default disk size is 8G, but the disk space allocation is only "as needed" up to 8G. The type of files created to represent virtual disks are called sparse files, consisting mostly of zeros. The unused space can be used for other operating system purposes. If you want a potentially larger VM disk, use the option:
$ uvt-kvm create ... --disk size     (size in gigabytes)
You can see the actual disk image files and their "virtual" sizes by running:
$ sudo ll -h /var/lib/uvtool/libvirt/images/
To see the "actual" sizes, use the du -h command:
$ sudo du -h /var/lib/uvtool/libvirt/images/*
For example, the Wordpress VM we're creating in the next section occupies about 900MB when installed.

Control by virsh

It is easy to stop/start machines from VMM, but you can also use the shell-based virsh tool to control the virtual machines from a non-GUI environment. For example, start our guest by:
$ virsh start vm
Get a list of all VM's by:
$ virsh list --all
Get a list of running VM's by:
$ virsh list
Shut it down by:
$ virsh shutdown vm
Have the virtual machine start on boot:
$ virsh autostart vm
virsh acts like a command shell in its own right if you activate it without parameters
$ virsh
virsh # help

Delete a VM

For proof of concept, this is how you delete a virtual machine created in this way:
$ uvt-kvm destroy vm
Doing this is WAY to easy, be careful with this command!

Help! If you somehow really screwed things up so that you cannot access your virtual machine, here is suggested fix:
$ sudo apt purge --auto-remove uvtool

Build a Wordpress Virtual Machine

This demonstration project illustrates several interesting new features: We'll call the dedicated VM wp. Once it is created, it's most convenient to leave two shells open, one on the host and other on the guest.
[MACHINE]$ ...
    [wp]$ ...

Create wp

Follow the procedure we've laid out:
[MACHINE]$ uvt-kvm create wp release=xenial --memory 256

[MACHINE]$ uvt-kvm ssh wp --insecure

[wp]$ sudo apt update
For the sake of expediency, we'll omit the upgrade.

Note that user is ubuntu and that you didn't have to give the password for sudo usage, how is that? The gimmick is a special control file in the /etc/sudoers.d directory. Observe:
[wp]$ sudo su
[wp]# ls /etc/sudoers.d/
[wp]# cat /etc/sudoers.d/90-cloud-init-users
The uncommented line means that the ubuntu user can use sudo to run all commands without giving a password.

Change networking on wp

We want to change the networking information, setting a static IP address.
[wp]$ sudo nano /etc/network/interfaces
The current file content is:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# Source interfaces
# Please check /etc/network/interfaces.d before changing this file
# as interfaces may have been defined in /etc/network/interfaces.d
# See LP: #1262951
source /etc/network/interfaces.d/*.cfg
The main network interface is defined in the auxiliary file:

auto lo
iface lo inet loopback
auto ens3
iface ens3 inet dhcp
Edit the main networking file. Comment out the source statement and add code which sets a static IP address

#source /etc/network/interfaces.d/*.cfg
auto ens3
iface ens3 inet static
Reboot the virtual machine (it's quite fast):
[wp]$ sudo reboot
Test to ensure connectivity:
[MACHINE]$ ping
If OK, assign a name to this IP address on your host machine. Edit /etc/hosts, adding this line:

/etc/hosts (on MACHINE)
...    wp
Also, add another entry to ~/.ssh/config to set the user correctly for access to wp:

~/.ssh/config (on MACHINE)
host wp
  user ubuntu
Then test to confirm that you can enter the guest like this:
[MACHINE]$ ssh wp

Open MySQL on host to external network access

First, we have to allow MySQL on the host to be accessed externally, in particular, from the virtual machine. To do so edit the MySQL configuration file
Look for the line:
bind-address =
Comment it out:
#bind-address =
Then restart MySQL:
[MACHINE]$ sudo systemctl restart mysql
Without this step, clients can only connect to the database from localhost.

Set up the wordpress database on host

Next, we want to create a dedicated database for wordpress. Again, we need user/password credentials. After installation, you do not need to remember these credentials.
Wordpress DB Password:
Create the following file (say in your home directory):

Run it on the host:
[MACHINE]$ sudo -H mysql < wordpress.sql
Test access from the host machine:
[MACHINE]$ mysql -u wordpress -pWP_DB_PASS wordpress
On the guest machine, install the MySQL client package:
[wp]$ sudo apt install mysql-client
The test access from the guest machine:
[wp]$ mysql -h -u wordpress -pWP_DB_PASS wordpress

More info To better understand what is going on, query the mysql database:
[MACHINE]$ sudo -H mysql mysql
mysql> select user,host from user; 
mysql> select user,host,db from db;
Note the presence of the wildcard "%" in the host fields for both tables. It means that the wordpress user can access MySQL from any host, and that the wordpress database accessed by the wordpress user can be accessed from any host.

Install and configure Wordpress in the guest

[wp]$ sudo apt install wordpress
Once this is done, create an Apache configuration file defining the URL "/discussion" for the site implemented by wordpress:

/etc/apache2/conf-available/wordpress.conf (on wp)
Alias /discussion /usr/share/wordpress
<Directory /usr/share/wordpress>
  Options FollowSymLinks
  AllowOverride Limit Options FileInfo
  DirectoryIndex index.php
  Require all granted
<Directory /var/lib/wordpress/wp-content>
  Options FollowSymLinks
  Require all granted
Enable this .conf file:
[wp]$ sudo a2enconf wordpress
Create the following wordpress configuration file. Note the presence of the wordpress user/database password, WP_DB_PASS in clear text (common to CMS systems).

/etc/wordpress/config-wp.php (on wp)
define('DB_NAME', 'wordpress');
define('DB_USER', 'wordpress');
define('DB_PASSWORD', 'WP_DB_PASS');
define('DB_HOST', '');
define('WP_CONTENT_DIR', '/usr/share/wordpress/wp-content');
Restart Apache:
[wp]$ sudo systemctl restart apache2
You can now "forget" the Wordpress DB Password with respect to this document.
Wordpress DB Password:

Configure the Wordpress site

Access and configure wordpress from the host vial the URL:
Running the site the first time will ask to set up an administrative user and other parts. Like in Drupal, you need a password, so I would again recommend your machine's login password, since this is again encrypted in the wordpress database.
Site Tite



Confirm password (if necessary):
Confirm usage of weak password    



Finally, log in to confirm. We're not going to set up anything specific.

Make wp externally accessible

Enable mod_proxy_http on the host (it's probably already done):
[MACHINE]$ sudo a2enmod proxy_http
We assume you've created a "local.conf" Apache config file and made it accessible in /etc/apache2 via a symbolic link; otherwise, set it up. Append this to the host's /etc/apache2/local.conf file:

/etc/apache2/local.conf (appended)
ProxyPreserveHost On
ProxyPass  /discussion   http://wp/discussion
Restart Apache on the host:
[MACHINE]$ sudo systemctl restart apache2
On the guest machine, wp, create another wordpress file specific to the new URL we want to apply. We can use config-wp.php as the basis and append to it:
[wp]$ sudo su
[wp]# cd /etc/wordpress
[wp]# cp config-wp.php config-MACHINE.php
[wp]# cat <<END >> config-MACHINE.php 
The modification adds two new configuration settings to force the new URL to be maintained through the site usage. Verify:
[wp]# cat config-MACHINE.php
Now you should be able to access wordpress using the URL:
Try accessing and logging into this site to verify that the base URL is maintained. This URL is also available externally from any taz client.

Tunnel Access

If you want to access this through the taz tunnel via:
you have to create yet another wordpress configuration file:
[wp]$ sudo su
[wp]# cd /etc/wordpress
[wp]# cp config-wp.php config-localhost.php
[wp]# cat <<END >> config-localhost.php 
Then verify:
[wp]# cat config-localhost.php

© Robert M. Kline