VLAN DMZ on Debian Virtual Server with Qemu and Libvirt

I have a set of virtual servers running on a single home physical server. I like to be able to remote into my home servers when I’m away from home so that I can get to the home automation if I need to. So one of my virtual servers is internet facing – I have a port on my router mapped through to ssh on that server.

I had thought I had configured that server with public key logon only to the ssh, but apparently I hadn’t, and I got a breach on that server. Which is embarrassing. So I decided to do a solid pass through the security of my environment.

My desire is to run a DMZ network, with only a jump-box machine in the DMZ visible to the internet. This machine will be locked down tightly, and only permit ssh off that machine to a single machine in the inner network zone. No root login will be permitted on any ssh. That means that a penetration of the environment would require cracking the public key logon on the jump-box, then cracking the username/password of the single machine that is connectable from that jump-box.

I’ll walk through the configuration I did there, but a key in all this is that it means my host server (the physical machine that hosts the virtuals) is actually connected to both the inner network and the DMZ network. But I don’t want that machine answering any connections on the DMZ network – that would effectively put the physical host into the DMZ. The hardest thing in this setup was having virtual servers that are on the DMZ network without having the host itself on that network.

So, configuration that I did. I am using a single physical network interface on the host, and I want from that:

  • The physical network interface itself. I’d like this to not get an IP address, as I don’t want it to be routable
  • A bridge interface build from the physical network, with a DHCP address on the inner network, this is on VLAN 1 / default. This bridge is made available to all virtual machines that are on the inner network
  • A virtual network interface that is build from the underlying physical network interface, but that is tagged to be on VLAN 3 (my DMZ). All traffic that transits this interface will be VLAN 3 without any configuration needed to be done on the individual machines. I don’t want this interface to be routable – I don’t want the host iself
  • A bridge interface build from this virtual network interface, allowing virtuals to be on this DMZ (VLAN 3). I don’t want this routable directly from the host, as I don’t want the host on the DMZ network

To achieve this, I have configuration in both /etc/network/interfaces, and in /etc/dhcpcd.conf. Both of these are involved in network routing and DHCP addresses, and I found that if I just create bridge configuration in the interfaces file then dhcpcd will still grab that bridge and allocate an IP address to, making it a routable interface.

Note that I did play around with using the nogateway directive in dhcpcd.conf, and with using post-up hooks to delete the routes after they were created. Neither of those gave the result I wanted.

Here is my configuration in /etc/network/interfaces:

# 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

auto enp3s0
iface enp3s0 inet manual

# iface enp3s0 inet manual

# vlan network interface - the .3 automatically tells it what to tag (apparently) - 3 is DMZ
auto enp3s0.3
iface enp3s0.3 inet manual

# The primary network interface
auto br0
iface br0 inet dhcp
  bridge_ports enp3s0
  bridge_stp off
  bridge_maxwait 0
  bridge_waitport 0
  bridge_fd 0
  metric 10
  pre-up /sbin/ifconfig enp3s0 mtu 9000

# the vlan bridge - DMZ
auto br0-3
iface br0-3 inet manual
  bridge_ports enp3s0.3
  bridge_stp off
  bridge_maxwait 0
  bridge_waitport 0
  bridge_fd 0
  metric 1000
  pre-up /sbin/ifconfig enp3s0.3 mtu 9000

This defines my primary interface enp3s0, but tells it that I want a manual IP address – in other words, please don’t allocate an IP address from this service. Note that if you only do this, dhcpcd will still allocate an address, so we need more configuration in dhcpcd.conf.

Then it defines a bridge br0 from that interface. This is the primary network connection that this server uses, and also the bridge used for any virtual that is on the inner network. This gets it’s IP address from DHCP, my DHCP server allocates a static address based on MAC.

Next, I define a virtual network interface on my DMZ network VLAN 3, enp3s0.3. It appears that the .3 on the end of the interface is how you tell it that you would like it tagged to VLAN 3, there isn’t some sort of tag directive. Again, I don’t want an IP address for this interface, I don’t want the host answering on the DMZ network.

Finally, I define a virtual bridge br0-3 on the virtual network interface, giving me a bridge that I can make available to my virtual servers that I want on the DMZ network.

Now, I need to do configuration in /etc/dhcpcd.conf to tell it which of these devices I want to have IP addresses. I am also blocking ipv6, because I haven’t worked out yet what firewalling I’d need on this.

interface br0
  noipv6

interface enp3s0
  noipv4
  noipv6

interface enp3s0.3
  noipv4
  noipv6

interface br0-3
  noipv4
  noipv6

So we have interface br0, which we are happy to have an ipv4 address (the only addressable interface) but we don’t want an ipv6 address on it. Then our other three interfaces all have no ipv4 or ipv6 on them, meaning they’re not routable at all.

We can check the routing that we get by using ip route:

root@server:/home/paul# ip route
default via 192.168.1.1 dev br0 proto dhcp src 192.168.1.4 metric 10 
default via 192.168.1.1 dev br0 metric 10 
192.168.1.0/24 dev br0 proto dhcp scope link src 192.168.1.4 metric 10 
root@server:/home/paul# 

This is telling us that the only routes available are via the gateway on the inner network (192.168.1.1), and via br0 with its IP address. Prior to this configuration you would have seen here something more like:

paul@server:~/ansible$ ip route
default via 192.168.1.1 dev br0 proto dhcp src 192.168.1.4 metric 10 
default via 192.168.1.1 dev enp3s0 proto dhcp src 192.168.1.148 metric 202 
default via 192.168.3.1 dev enp3s0.3 proto dhcp src 192.168.3.148 metric 204 
default via 192.168.3.1 dev br0-3 proto dhcp src 192.168.3.201 metric 206 
192.168.1.0/24 dev br0 proto dhcp scope link src 192.168.1.4 metric 10 
192.168.1.0/24 dev enp3s0 proto dhcp scope link src 192.168.1.148 metric 202 
192.168.3.0/24 dev enp3s0.3 proto dhcp scope link src 192.168.3.148 metric 204 
192.168.3.0/24 dev br0-3 proto dhcp scope link src 192.168.3.201 metric 206 

This is what I had before I started the dhcpcd.conf changes, and it meant the host server was answering on all 4 interfaces, and it was very hard to work out what was going on / where network traffic was going.

Openhab Heating Configuration

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post I cover a detailed configuration of Openhab for heating purposes.  We create the rule sets to allow us to have an arbitrary number of zones, with each zone having 4 setpoints at configurable times during the day.  The zones push those setpoints down to the devices in the zone.  We allow people to change the temperature in a zone using the wall thermostat, but override again at the next timed change.

We also control the running of the boiler based on how many valves are open – this is to avoid the boiler short cycling when there are very few valves or valves only partly open.  We’ll cover this in more detail when we get to the relevant rules.

We create a sitemap that gives us access to most of this information.

Continue reading

Configuration of MAXCUL and CUL Dongle

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post I cover the installation of the firmware for the CUL dongle (culfw), the programming of the dongle to work with your raspberry pi, and configuration of the maxcul binding for Openhab.

At the end of this tutorial you should have one wall thermostat and one radiator valve paired to your raspberry pi via the CUL dongle.

Continue reading

Installing Openhab on Pi

This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house.  Refer to the index here.

In this post we install a new Raspberry Pi from scratch, and get OpenHab running on it.  We choose to use Wifi, and we install it headless (no GUI and no monitor).  We install by connecting the card reader to a linux machine, which gives us access to the file system as we build it.

Continue reading

Using Pi and OpenHab to control radiators and watering

Our house has hydronic radiator heating, we also have a watering system and other equipment.  I wanted to use a Raspberry Pi to control the heating, as our radiators previously had manual valves.  I also wanted to control the garden watering system whilst I was at it.

This tutorial series will cover the process of installing and configuring the software to achieve this, with topics being:

 

Exporting playlists from mythmusic

In my new house I don’t have any free to air TV – reception is too poor.  So my mythtv installation is less useful than it could be – it’s primarily a setup that records TV.  It also plays music, but it’s not inspiring at it.

My frontend died and needed replacing, and after fighting for a while I couldn’t get LIRC/remote controls going with the new hardware.  I looked around and Kodi (an evolution of XBMC) looks to have a really good remote app that goes on my iPhone.  Way better.

I’ve installed Kodi and it’s working well after some fiddling around.  But I had a lot of music playlists in mythtv.  I want them in Kodi.  Kodi can import standard m3u playlists, mythtv doesn’t have a standard export for them.

After googling around a bit, I decided to write a perl script that does it.  Without further ado, here it is for anyone that might need such a thing.

#!/usr/bin/perl
use strict;
use warnings;
use DBI;

# MySQL database configuration
my $dsn = "DBI:mysql:mythconverg";
my $username = "root";
my $password = 'Massey01';

# path prefix - haven't dealt with storage groups, so set this to your storage group path
my $prefix = "/usr/share/mythtv/server/mp3/";

# connect to database
my $dbh  = DBI->connect($dsn,$username,$password);

# create temporary table for holding song list
my $sql = "CREATE temporary table tmp_playlist_songs (
  playlist_id int(11),
  playlist_name varchar(255),
  song_id int(11)
)";
my $create_table = $dbh->prepare($sql);

# create the table
$create_table->execute();
$create_table->finish();

# setup the insert statement ready for use
$sql = "INSERT INTO tmp_playlist_songs( playlist_id, playlist_name, song_id )
        VALUES (?,?,?)";

my $insert_stmt = $dbh->prepare($sql);

# select all playlists from the database
$sql = "SELECT playlist_id,
               playlist_name,
               playlist_songs
           FROM music_playlists";
my $get_playlists = $dbh->prepare($sql);
# execute the query
$get_playlists->execute();

my $playlist_id;
my $playlist_name;
my $playlist_songs;

# iterate over each playlist
while( my @row = $get_playlists->fetchrow_array() ) {
  $playlist_id = $row[0];
  $playlist_name = $row[1];
  $playlist_songs = $row[2];

  my @songs = split( ',', $playlist_songs );

  # insert the songs into the temporary table
  foreach my $song ( @songs ) {
    $insert_stmt->execute($playlist_id, $playlist_name, $song);
  }

  # select out the song filenames
  $sql = "SELECT path, filename FROM
            tmp_playlist_songs,
            music_songs,
            music_directories
          WHERE
            tmp_playlist_songs.song_id = music_songs.song_id AND
            music_songs.directory_id = music_directories.directory_id";
  my $get_playlist_detail = $dbh->prepare($sql);

  $get_playlist_detail->execute();

  open my $file_handle, ">$playlist_name.m3u";

  while( my @song_row = $get_playlist_detail->fetchrow_array() ) {
    print $file_handle $prefix . $song_row[0] . '/' . $song_row[1];
    print $file_handle "\n";
  }
  $get_playlist_detail->finish();

  close $file_handle;

  # clear out the temporary table
  $sql = "DELETE FROM tmp_playlist_songs";
  my $delete_playlist = $dbh->prepare($sql);
  $delete_playlist->execute();
}
$get_playlists->finish();
$insert_stmt->finish();

# disconnect from the MySQL database
$dbh->disconnect();

Hope it’s useful for someone.

Using protractor to e2e test ui-grid 3.0 (ng-grid)

In my previous post I described upgrading to ui-grid 3.0, which is the not-yet-beta version of ng-grid.  Over time this will offer significant benefits, at the moment it feels like a faster ng-grid.  As part of implementing it on my core application I needed to rewrite the library routines for my end-to-end testing using protractor.  These were reasonably tricky to work out, so I thought I’d post them here for anyone else trying something similar.

Continue reading

Upgrading to ng-grid 3.0 (ui-grid)

In this tutorial segment I upgrade the league application to use the new ui-grid (ng-grid 3.0).  Note that ui-grid is at this time still early beta, but offers the likelihood of better performance, a cleaner interface, easier edit in place, and removes the previous dependency on jQuery.

This code is built on the rails4 tutorial that I have previously written, and in particular uses as a starting point step 10 of that tutorial, which is available at github: PaulL : tutorial_10.

Continue reading