Home Lab: CentOS 6.3 as a firewall and Router

Here's how I setup CentOS 6.3 as a firewall/router in my home lab.  I've got a standalone server running VMware ESXi with a few VMs on it.  I wanted to setup a protected subnet behind a firewall, so that I could test some security configurations.  Virtualization makes things pretty easy, in that it enables us to build the VMs as well as the virtual network switches quickly and without a lot of expensive hardware.  The design I was shooting for was pretty simple, as shown in the image below.



Home Network with Virtual Firewall protected Subnet
So for starters, I had my ESXi server and my first virtual switch (vSwitch0) which is uplinked to my home network.  My home network is simply your typical wireless router with a few hard Ethernet ports in the back, into which my cable modem and my ESXi server are connected.  As is typical, my home network uses the 192.168.1.0/24 subnet, so my ESXi server, the VMs, and my laptop are all on that subnet.

Now to setup a protected subnet, the first thing we need is another switch, so I created a second virtual switch (vSwitch1).  Now this new switch is not uplinked to my home network, it's completely isolated.  We're going to provide it with connectivity via a VM built as a firewall/router.

So I added two new VMs, the firewall/router and a protected VM for testing.  The firewall/router VM is connected to both the home network switch and the isolated switch (so it can forward traffic between the two), and the protected VM is connected to the isolated switch.  The resulting design (as shown in the ESXi network configuration) is shown in the image below:
Home Lab Network Configuration

OK that was the easy part.  Now for a little planning.  In order to route from my home subnet to my isolated subnet, I need a new range of IP addresses for the new subnet.  I decided to use 10.0.0.0/24.  The whole 10 subnet, like the 192.168 subnet, is not routed on the Internet, and so is safe to use for private networks.

Building the Router
Now the next thing to do is to install and configure the OS for the firewall/router.  I decided to use CentOS 6.3 minimal for this, since it's quite small and can run without much memory (I don't have much RAM in my ESXi box).

I won't get into the basic OS install, it's dead simple.  However, by default, the network interfaces are down (in CentOS 6.3 minimal they are, not the friendliest linux distro...).  So the first step is to get the NICs online.

Network Interfaces
To setup the interfaces, we log into the router as root, go to the /etc/sysconfig/network-scripts directory, and  edit the ifcfg-eth0 file.  eth0 is the interface on the home network, so I'll give it a 192.168.1.x address and use the wireless router as the default gateway.  Here's what the resulting file looks like:

DEVICE="eth0"
BOOTPROTO="none"
HWADDR="00:0C:29:8C:58:56"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
UUID="d29f1d45-ff81-4123-b7ac-0eb3a76c170c"
IPADDR=192.168.1.121
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DEFROUTE="yes"

Next, we configure the other interface. This time, we edit the file ifcfg-eth1 and setup and give it a 10.0.0.x address.  In this case, notice there's no default gateway, we want all traffic bound for other subnets heading out the other interface.  The resulting file is shown below:

DEVICE="eth1"
BOOTPROTO="none"
HWADDR="00:0C:29:8C:58:60"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
UUID="0c740b11-7173-4f91-9b84-c70daa0d669a"
IPADDR=10.0.0.1
NETMASK=255.255.255.0

OK, assuming that we didn't get the interfaces reversed, we should now have two live interfaces, pingable from their respective subnets.  The default firewall rules on CentOS 6.3 should allow icmp so pings should be successful.  However, we don't quite have a router yet, now we need to configure CentOS to forward packets.

Kernel Forwarding
By default, the linux kernel is configured not to forward packets between interfaces.  This is usually a good thing, as you wouldn't want every linux box to act like a router, but we do in this case.  The file that controls kernel behavior with respect to ip networking is /etc/sysctl.conf.  We edit the file and find the line that reads net.ipv4.ip_forward = 0 and change the 0 to a 1.  Now the next time we reboot, the kernel will forward packets.  However, there's still one more thing that will stop us from forwarding, the iptables firewall on CentOS.

Firewall Adjustments
By default, the iptables rules on CentOS reject packet forwarding.  We can change the rules to allow all forwarded packets, in which case, we've just got a wide open router.  Or we can set specific rules to allow certain traffic, which is what I set out to do in the first place.

So we need to decide what traffic we want to pass through.  My protected VM doesn't have any services on it at this point, like apache or mysql, so for now, I just want to be able to SSH into it from my laptop on the home network, and I want the protected VM to be able to get out to the Internet so it can get updates from the yum repositories.

To allow all that, we need to allow SSH (tcp port 22), HTTP (tcp port 80) and oh yeah, we'd better let DNS (udp/tcp port 53) through so that the protected VM can resolve the addresses of the yum repository URLs.  I'll also allow pings through for troubleshooting purposes.  We edit the file /etc/sysconfig/iptables.  Here's what the resulting file looks like:

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -i eth0 -o eth1 -p tcp --dport 22 -j ACCEPT
-A FORWARD -i eth1 -o eth0 -p tcp --sport 22 -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -i eth1 -o eth0 -p tcp --dport 80 -j ACCEPT
-A FORWARD -i eth0 -o eth1 -p tcp --sport 80 -j ACCEPT
-A FORWARD -i eth1 -o eth0 -p tcp --dport 53 -j ACCEPT
-A FORWARD -i eth1 -o eth0 -p udp --dport 53 -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

The FORWARD lines are the bits that we've added.  The other lines at the top of the file are defaults from the CentOS install.  Notice that I added my forwarding rules above the final FORWARD REJECT line at the end, which rejects everything I haven't explicitly accepted.  For each of our ports, there are two rules, one for originating traffic and one for return traffic.  We're almost done.

Routing Tables
Finally, we need to tell all the devices on our network where to send packets when they want to talk to devices on the other subnet.  For devices on our new isolated subnet, we simply use the router's interface as our default gateway, which is 10.0.0.1.  For example, I'll give my protected VM an IP address of 10.0.0.2, a subnet mask of 255.255.255.0, and a default gateway of 10.0.0.1.  The protected VM will therefore send packets to the router for any address that's not on the 10.0.0.0/24 subnet.  And, since the router's default gateway is pointed at the wireless router, it will send packets to that router for anything not on 10.0.0.0/24 or 192.168.1.0/24.  Good deal.

But what about my laptop, trying to SSH to the protected VM.  How does my laptop know where 10.0.0.0/24 is?  It doesn't.  Also, traffic returning to the protected VM from the Internet doesn't know how to get there either.  We have to add a route to the wireless router.

Now, you network guys, remember this is a home network.  I'm not going to deploy a dynamic routing protocol like BGP or EIGRP on my little CentOS VM and try to setup a peer relationship with my wireless router.  Perhaps I could, there are certainly linux packages for that stuff, but that's beyond what we need for a home lab.  What I decided to do was to simply add a static route to my wireless router.  Happily, there was a configuration page for that in my wireless router (under advanced routing).  I simply needed to add a route for 10.0.0.0, subnet mask 255.255.255.0, pointing to the home side of my CentOS router (which is at 192.168.1.121).

Performance Issues
You may run into performance issues passing traffic through your virtual router.  I sure did.  I found that forwarding performance was very slow.  I tried various virtual network adapter types (E1000, VMXNET3), and some TCP offload settings within Linux until I found the solution.  Choose the E1000 adapter type for the router interfaces, then turn off tcp-segmentation-offload on both interfaces using the following two commands at the linux command line of the router (as root):

ethtool -K eth0 tso off
ethtool -K eth1 tso off

Of course, I think this performance tip is probably only valid for a virtual router.  The opposite is probably true for a router running on a physical computer, that is, if the Ethernet cards are capable of TCP offload.

Result!
That did the trick for me!  I'm able to ping and SSH into my protected VM, and the protected VM is able to ping out to the world and download updates.  Now I can deploy services on the protected VM, tweak the firewall rules to allow the associated traffic, and do security testing to my heart's content.

Related Posts:

5 comments:

Anonymous said...

Hello !!, i've the same config, but nothing.... i can ping only from "home"to protect" but from the protect vm to home network, nothing to do
Using esxi 5.5 ( exaclty configured as shown in your picture )
Router with centos 6.7
Protected vm both win and linux
any idea ?
Thanks

Brian said...

Make sure your protected VMs are using the router's IP address (on the protected subnet) as their default gateway. Also, if you want to post your iptables file that might help.

Ken said...

hi, i know this is old thread. this is exactly i am setting up. but struggling with adding the route.
can you share the route command that you executed?

Brian said...

Hi Ken, are you setting this up on a home network or a corporate network?

Mohawk Man said...

Thank you so much for this guide, I had a problem with SSH restricting SSH to one way traffic from eth1 t0 eth0. I couldn't figure out why when I had FORWARD ACCEPT [0:0] as a rule it would work but when I narrowed it down to -i eth1 only ssh would hang. Seems so obvious now, how else could it communicate! Thanks again!

Post a Comment

Related Posts Plugin for WordPress, Blogger...