KVM & Dynamic DNS: dynamic virtual machine naming

In my previous article, we saw how to provision KVM virtual machine with PXE. We have our own virtual machine deployment lab in our own laptop. And that’s great. Each time we create a virtual machine, we need to connect with Spice in order to get the private IP or use tool like nmap or check the ARP cache. If you need to deploy a lot of virtual machine, this will become a real hassle.

In this article, I will present you another solution for this problem : the dynamic DNS. We will install a DNS server on our hypervisor (here a laptop). This DNS server will register each virtual machine when it joins the network. Then, the virtual machine will get its hostname from the same DNS server. So you can decide what will be the machine name beforehand then deploy it and use this name to connect to it easily.

While Dynamic DNS is not advise to be deploy in a production environment because of security issues it can provoke, it is very suitable for a personal laboratory on our own network. Stop talking, get ready for action.

The DNS server we will use, on Debian or Ubuntu, is bind9.

sudo apt install bind9

First, we will edit the main configuration files /etc/bind/named.conf

acl internals { 127.0.0.0/8; 10.250.12.0/24; };

controls {
    inet 127.0.0.1 port 953 allow { 127.0.0.1; };
};

include "/etc/bind/chafouin.org-rndc.key";

include "/etc/bind/named.conf.default-zones";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.options";

This is the main configuration file, it loads few others files we will edit later, the key use by DNSSEC and limit the control ACL to localhost.

Then, in order to authenticate request coming from the DHCP to the DNS server, we will create a RDNC key. Let’s generate it.

dnssec-keygen -a HMAC-MD5 -b 512 -n USER chafouin.org-rndc

It will create 2 files, one private and one key. Edit the file /etc/bind/chafouin.org-rndc.key and put the private key in it.

key "chafouin.org-rndc.key" {
        algorithm hmac-md5;
        secret "<secret_key>";
};

Remove world readable right.

chmod 600 /etc/bind/chafouin.org-rndc.key

Let’s continue our bind configuration with /etc/bind/named.conf.options

options {
	directory "/var/cache/bind";

	query-source address * port *;

	forwarders {
	    8.8.8.8;
        8.8.4.4;
	};

	dnssec-validation auto;

	auth-nxdomain no;
    listen-on-v6 { none; };
    listen-on { 127.0.0.1; 10.250.12.254; };

    allow-transfer { none; };
    allow-query { internals; };
    allow-recursion { internals; };

    version none;
}

This file contains some bind server general configurations: the working directory, the authorize query sources, the DNS server where unknown domain requests will be forwarded, if DNSSEC is enabled or not, the interfaces where the server will listen, who is allowed to send AXFR transfert, domain request and recursive queries. You should read the bind manual for more informations.

Now, let’s edit /etc/bind/named.conf.local. This is where you will create your DNS zone and allow the DHCP to update the DNS list.

zone "chafouin.org" {
        type master;
        file "/var/cache/bind/db.chafouin.org";
        forwarders {};
	    notify no;
        allow-update { key chafouin.org-rndc.key; };
	    allow-query { any; };
};
zone "12.250.10.in-addr.arpa" {
        type master;
        file "/var/cache/bind/db.chafouin.org.inv";
        forwarders {};
	    notify no;
        allow-update { key chafouin.org-rndc.key; };
	    allow-query { any; };
};

include "/etc/bind/zones.rfc1918";

Then, we will create our two DNS zone files, one for DNS resolution and the other one for reverse DNS resolution.

Edit /etc/bind/db.chafouin.org. This file contains the DNS rules, it will be updated on-the-fly by the dynamic DNS system.

$TTL    3600
@       IN      SOA     chafouin.org. chafouin.org. (
                     2017052701         ; Serial
                           3600         ; Refresh
                            600         ; Retry
                          86400         ; Expire
                           3600 )       ; Negative Cache TTL
;
@       IN      NS      ns.chafouin.org.
ns      IN      A       10.250.12.254

And /etc/bind/db.chafouin.org.inv. Same principle but for reverse DNS rules.

$TTL    3600
@       IN      SOA     chafouin.org. root.chafouin.org. (
                     2017052701         ; Serial
                           3600         ; Refresh
                            600         ; Retry
                          86400         ; Expire
                           3600 )       ; Negative Cache TTL

@               IN      NS      ns.chafouin.org.
1               IN      PTR     ns.chafouin.org.

Then link the file to the right place.

ln -s /etc/bind/db.chafouin.org /var/cache/bind/

ln -s /etc/bind/db.chafouin.org.inv /var/cache/bind/

The DNS server is ready, we must apply some changes in the DHCP configuration.

option domain-name "chafouin.org";
option domain-name-servers 127.0.0.1;

default-lease-time 600;
max-lease-time 3600;
server-name "chafouin-dhcp-server";

ddns-updates           on;
ddns-update-style      interim;
ignore                 client-updates;
update-static-leases   on;

authoritative;

allow bootp;
allow booting;

include "/etc/dhcp/chafouin.org-rndc.key";

zone chafouin.org. {
  primary 127.0.0.1;
  key chafouin.org-rndc.key;
}

zone 12.250.10.in-addr.arpa. {
  primary 127.0.0.1;
  key chafouin.org-rndc.key;
}

subnet 10.250.12.0 netmask 255.255.255.0 {
  range 10.250.12.100 10.250.12.200;
  option subnet-mask 255.255.255.0;
  option broadcast-address 10.250.12.255;
  option routers 10.250.12.254;
  option domain-name-servers 10.250.12.254;
  ping-check = 1;
  filename "pxelinux.0";
  next-server 10.250.12.254;
}

This file is quite the same as the previous article about PXE boot, we just made few modifications in order to add dynamic DNS. This is DHCP server that will update the DNS rules files each time a new virutal machine is joining the network.

You are now all set. You can try to launch a virtual machine, when the setup is complete, the machine will restart and its DNS name will be added to the DNS server. Here the DNS entry will look like <machine_hostname>.chafouin.org.

When a virtual machine is provisionned by the PXE, the preseed file set the machine hostname to debian. If we start 2 virtual machines in the same time, both will try to add the same entry in the DNS server. How can we choose our machine name then ?

My workaround is simple : we will use the TFTP server and the last_command field in the preseed configuration in order to get and set the hostname at the end of the installation. When the machine will reboot, it will have a new hostname, without conflict.

Create a new folder in the TFTP path :

mkdir /srv/tftp/hostnames

This folder will contains one file per VM, named by the VM MAC address. It will contains its hostname.

Let’s change the preseed configuration to make the installer get the hostname corresponding to the machine. Edit the following line in the /srv/tftp/config/debian/debian-jessie-preseed.cfg

d-i preseed/late_command string chroot /target sh -c 'sed -i "s/PermitRootLogin without-password/PermitRootLogin yes/g" /etc/ssh/sshd_config; /usr/bin/curl -s tftp://10.250.12.254/hostnames/$(ip a s eth0 | grep link/ether | cut -d " " -f6) > /etc/hostname; sed -i "s/127.0.1.1\\tdebian/127.0.1.1\\t$(/usr/bin/curl -s tftp://10.250.12.254/hostnames/$(ip a s eth0 | grep link/ether | cut -d " " -f6))/g" /etc/hosts'

Now, each time we will create a virtual machine, we will get its MAC address with virsh and we will add the hostname we want in a file named by its corresponding MAC address before the installation end and it will do the trick !

echo 'labtest' > /srv/tftp/hostnames/$(virsh domiflist <machine_name> | grep br0 | cut -d ' ' -f30)

We now have a functional dynamic DNS in our KVM setup, we can now easily setup our virtual machine with a minimum manipulation. Create your xml template, create your virtual machine, launch it, select the right OS in the PXE menu then run the command to set the hostname, wait few minutes and you have a brand new virtual machine ready to be used, just connect to it using its domain name and you are good.

References

https://wiki.debian.org/Bind9 https://wiki.debian.org/DDNS