Background
I’ve had a home-made Internet firewall for a long time, but it’s getting old and one day it’s just going to fail, so I decided that it’s time to update it. The old firewall was just a PC running Linux and using iptables to manage the rules. Actually, when I say “old”, I’m not really kidding. The specs of the machine are:
Pentium processor running at 150MHz 64M RAM 630MB hard disk Running RedHat 7.1 (released late 2001) Installed and running since April 2002 So, it’s coming up for 13 years old which I think means it’s done pretty well for itself!
Hardware
So I started looking around for some hardware options for a replacement. I looked at some dedicated firewall router boxes, but didn’t really like the functionality (or price). I’m also somewhat concerned about poor security, the possibility of “maintenance” back-doors, and the inability to know exactly what rules are being implemented. The alternative is to do what I did before, which was to implement my own firewall on a general purpose computer. There are some small form factor computers around (for example, Alix 2-3), but then someone at work pointed me at the Banana Pi BPI-R1 router board. It’s based on the rather well-known Raspberry Pi, but with the following features:
dual core CPU 1G RAM 4 LAN, 1 WAN Ethernet connections on-board space for a SATA drive And all for $145 including a case. That’s cheap enough to buy a second unit to act as a hot spare (I can be a bit anal about things like that…).
So I ordered one and started working out the requirements.
Design thoughts
I could have just installed a dedicated firewall solution like OpenWRT, but in the end I decided to roll my own solution.
The OS resides on a micro SD card, so you need to take some precautions to avoid corrupting it, otherwise a poorly-timed power outage could cause some writes to be lost and the server rendered unbootable. I decided to mount the entire SD card read-only to avoid this scenario. Plus there are obvious security advantages in this – any attack that requires writing something to the filesystem is automatically blocked. It makes maintenance and updates a bit harder, but you can always remount the filesystem in read-write mode temporarily to make the required changes.
The firewall will block all connections by default, with only explicitly-allowed connections allowed through. This is even for outgoing connections, which can be a bit annoying when someone wants to connect to some unusual port outside, but I can live with that.
Access to the firewall needs to be strictly controlled, obviously. The ssh settings are locked down (no root logins, only listen to the internal network interface, only public key authentication is allowed). The only time a password is needed is for sudo access to root from the admin account. System logs are sent off-host to another server for security.
Apart managing connections between the outside and the inside (and DMZ), there are a few basic services that the firewall will need to support:
Provision of a caching forwarding DNS server for use by the firewall and internal computers Connection to an external NTP server for time synchronisation A DHCP client to obtain network information from the cable modem An SSH server for access from the inside Relaying of IMAPS connections from the outside to an internal mail server (so I can access my email from outside) My internal network is 192.168.13.0/24, and the DMZ network is 192.168.14.0/24. The address of the firewall on these networks is 192.168.13.5 and 192.168.14.1 respectively. The external interface is connected to a cable modem which provides a dynamic external address via DHCP.
I don’t currently have any machines to put on the DMZ, but that is likely to change in the future.
Installation process
These are the steps I followed to deploy the firewall.
Basic OS installation and configuration
I connected a monitor to the HDMI port, a USB keyboard/trackpad to the USB port, and a network cable to one of the LAN ports). I downloaded a suitable OS image (mattrix-bananian-14.11-BPI-R1.img) and wrote it to an 8G micro SD card. Note that it is important to get an image that is specific to the BPI-R1, as it includes tools and drivers for the special Ethernet controller. I stuck the SD card in the slot and powered up the board. The installer allows you to do some basic configuration which should be pretty straightforward. The only important thing for me was to make sure it had the right locale installed for me (en_AU.UTF-8).
VLAN setup
Once I could log in using the default password, I set up the network VLANs. Unlike some other machines, all the network interfaces belong to the same device (eth0), with their roles being defined by VLAN tags. Each socket has a port number, viewed from the front they are ordered as follows:
LAN WAN 2 1 0 4 3
I wanted to use the first port for inside, the 4th port for the DMZ and obviously last on is for the outside. The command to manage VLANs is swconfig, and the easiest way to set things is with the configuration file, /etc/network/if-pre-up.d/swconfig:
#!/bin/sh
# port ordering (view from front):
# [ 2 1 0 4 ] [ 3 ]
ifconfig eth0 up
swconfig dev eth0 set reset 1
swconfig dev eth0 set enable_vlan 1
swconfig dev eth0 vlan 101 set ports '2 8t'
swconfig dev eth0 vlan 102 set ports '1 8t'
swconfig dev eth0 vlan 103 set ports '0 8t'
swconfig dev eth0 vlan 104 set ports '4 8t'
swconfig dev eth0 vlan 201 set ports '3 8t'
swconfig dev eth0 set apply 1
This will create 5 network interfaces: eth.101 (inside), eth.102, eth.103 (both unused), eth.104 (DMZ) and eth.201 (outside).
Next I need to set up the networks for each of the interfaces. This is my configuration file, /etc/network/interfaces:
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
# WAN - external
auto eth0.201
iface eth0.201 inet dhcp
# VLAN 101 - internal
auto eth0.101
iface eth0.101 inet static
address 192.168.13.5
netmask 255.255.255.0
# VLAN 102 - unused
auto eth0.102
iface eth0.102 inet manual
# VLAN 103 - unused
auto eth0.103
iface eth0.103 inet manual
# VLAN 104 - DMZ
auto eth0.104
iface eth0.104 inet static
address 192.168.14.1
netmask 255.255.255.0
Now is a good time to reboot and make sure the networking stuff is set up the way I want.
There are a few packages that I needed to install that aren’t provided. We don’t have a connection to the outside world at this point, so I added a temporary default route via my current firewall and installed the packages:
# route add default gw 192.168.13.6
# apt-get install sudo
# apt-get install tcpdump
# apt-get install unionfs-fuse
# apt-get install bind9
Setting up users and authentication
Next I set up an “admin” user:
# useradd -m -u 510 -s /bin/bash admin
# passwd admin
(choosing a very secure password)
# su - admin
$ mkdir .ssh
$ chmod 700 .ssh
$ vi .ssh/authorized_keys
(add public key from a secure internal host)
$ chmod 600 .ssh/authorized_keys
I put generated a dedicated key-pair for access to the firewall, and gave it a passphrase, so that only I could use it.
As I will always be logging in as the admin user, I need to add admin to the sudoers file, using visudo, by adding the following line:
admin ALL = (ALL:ALL) ALL
Now is a good time to check that you can log into the firewall using the admin account and your private key, and that you can the use sudo to become root (e.g. run “sudo id”) using the secure admin password I created earlier.
The final step is to lock down ssh. I added /etc/ssh/sshd_config and ensured that it contains the following:
ListenAddress 192.168.13.5
PermitRootLogin no
PasswordAuthentication no
I then told sshd to reload its configuration:
# kill -HUP <pid-of-sshd>
I gave it a bit of a test to make sure it was all working.
Configure for read-only filesystem