How to configure internal network to isolate FreeBSD Jails and Virtual Machines from the public Internet.
If you're the kind that runs their own server on the public Internet, you have to worry about a whole bunch of concerns regarding security of your server and the services running on it. All to ensure your data and compute resources aren't abused. One layer of security that you can use to lock down your server is to run disparate services in separate containers that isolate the services from one another. That way, when any one of the services gets compromised or goes rogue because of a bug - rest of your services and the server itself do not come crashing down, nor is all of your data at risk.
Another layer in securing your services is an internal network. FreeBSD's container technology (Jails) has been available for 20+ years, and the lessons learned since then are baked into the system to make it robust and easy to administer Jails. The OS comes with built-in ways to create private networks within the host and over Virtual Private Networks (VPNs). We'll look at setting up a VPN in another post. I will also cover installing
vm (vm-bhyve) in later posts. This task is the prerequisite for having the base ready to do so.
Today, let's create a bridge where we can attach our Jails and VMs. What we want to achieve is an additional network interface available on our server. This interface is a bridge where
iocage can bind the jails. We will use
sysrc as described in previous post to set up the bridge and in next post, configure
pf - the Packet Firewall to selectively allow traffic in and out to the public Internet.
At the moment, the
/etc/rc.conf looks like this for my test VM:
# System clear_tmp_enable="YES" dumpdev="NO" hostname="freebsd12" # Services syslogd_flags="-ss" sendmail_enable="NONE" sshd_enable="YES" # Network ifconfig_vtnet0_name="public" ifconfig_public="DHCP"
ifconfig shows this output:
[root@freebsd12 ~]# ifconfig public: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=80028<VLAN_MTU,JUMBO_MTU,LINKSTATE> ether 58:9c:fc:08:9f:0a inet 10.0.166.170 netmask 0xffff0000 broadcast 10.0.255.255 media: Ethernet 10Gbase-T <full-duplex> status: active nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384 options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2 inet 127.0.0.1 netmask 0xff000000 groups: lo nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
We have renamed the
vtnet0 interface to
public since it connects to the outside world. The IP address on this VM is within the private network as it is a test VM, but if you're running a VPS, say on on Vultr.com, it will have a public IP.
Now we will create a bridge interface through
/etc/rc.conf and name it
private. We'll use the
sysrc utility to interact with the
This does not yet create the bridge, we can use
ifconfig to list all the interfaces and confirm that.
Next, we give the bridge a custom name
And finally, we configure the bridge with a private IPv4 address:
[root@freebsd12 ~]# sysrc ifconfig_private="inet 172.16.0.1 netmask 255.255.0.0" ifconfig_private: -> inet 172.16.0.1 netmask 255.255.0.0
These are the lines added to
/etc/rc.conf by our commands above:
cloned_interfaces="bridge0" ifconfig_bridge0_name="private" ifconfig_private="inet 172.16.0.0 netmask 255.255.0.0"
At this point we can reboot the VM.
Once it comes up, we can verify that we have one additional network interface:
And we can query the new interface to look at its properties:
[root@freebsd12 ~]# ifconfig private private: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 02:81:70:cd:50:00 inet 172.16.0.0 netmask 0xffff0000 broadcast 172.16.255.255 id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto stp-rstp maxaddr 2000 timeout 1200 root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0 groups: bridge nd6 options=9<PERFORMNUD,IFDISABLED>
We created the
private network interface for our Jails and VMs, however at the moment, it cannot pass packets to the outside world, we will look at configuring
pf to allow Network Address Translation (NAT) in the next post.