Is it possible to easily run a half-dozen internet services on a single piece of hardware and make sure that if one is compromised the others will remain unharmed? Can this be done without a mountain of administrative overhead and customization? Can I configure my services the way I have grown accustomed? Absolutely! This article will outline how to achieve this, through the use of FreeBSD Jails.
Over the course of this article I will outline how to install a list of production services on a single piece of hardware, securing each one from the next, all with only one additional administrative tool: ezjail
Before we get to the ezjail tool we need to define FreeBSD Jails. What are they? What do they do? Why do I care?
FreeBSD Jails are a kernel-level security tool used widely in the FreeBSD community to segregate processes. An easy way to think of a Jail is that it is very much like a chroot environment, but much more hardened. While a standard chroot environment can often be escaped, FreeBSD has added code to their kernel which hardens the chroot environment into a “Jail”—Inescapable. Within this Jailed environment processes are unable to identify, access or otherwise communicate with processes on the outside of the Jail. Networking is limited within the Jail as well. A Jail cannot affect any underlying network configuration other than that which it has been assigned. A Jail can also be thought of in many ways like a virtualized machine in that the virtual “guest” cannot interact with the physical “host”. Jails allow us the opportunity to run processes in a secure manner separate from our host environment.
If that sounds appealing to you may be wondering how to activate and use this Jail system. That, my friend, is the focus of this article. Get settled because by the time we’re done here you will have all the tools you need to segregate processes for security, sandboxing or even create custom environments for other users.
By default the Jail system is part of the FreeBSD kernel. The kernel customizations to make the system possible have such a minimal footprint that it was decided it should be a default, always-on feature of FreeBSD. Your FreeBSD installation already has the ability to do everything described above, you just need to know how to use it.
The tool that I use to create, manage and interact with my FreeBSD jails is called “ezjail”. It simplifies much of the underlying configuration of a Jail system to the extent that you can create a Jail and be working within it in just three steps!
To install the ezjail port you need to make sure you have your ports tree updated and then run:
cd /usr/ports/sysutils/ezjail && make install clean
Before we can create any Jails we’ll need to create the base Jail environment. This is the template environment from which all other Jails will be created. This is simplified by the ezjail-admin tool:
This will download the components of a base Jail system. Also, the -m, -s and -p options install the man pages, source packages and ports tree respectively. If you want access to these within your Jail environments then be sure to append them to the command above.
Before any Jails will be able to start you’ll also need to activate the ezjail system within the /etc/rc.conf. This is done using the command:
echo 'ezjail_enable="YES"' >> /etc/rc.conf"
Now that you’ve got the proper tools installed you’ll need to keep in mind the following requirements for creating and maintaining a Jail environment. These items will need to be defined for each Jail environment that you want to create, and will need to persist for the life of the Jail.
- IP Address(es)
- custom jailroot (storage directory) – optional
For our purposes here we’ll create three Jail environments. We’ll call them “larry“, “curly” and “moe“. Each of these will be assigned an IP address on our internal LAN using “192.168.0.100”, “192.168.0.101” and “192.168.0.102” respectively. We will also use the default jailroot path, which is /usr/jails/jailname/.
Based on the above decisions we have three of the items defined, but only two configured. We will need to create interface aliases for our network device which will bind to the addresses we’ve decided on. There are two ways this can be done. The first method, the temporary method, will work for quickly testing Jails and creating environments that you don’t need to keep. The second method, the persistent method, will define the interface aliases in your system configuration and define them persistently across reboots. The persistent method is what you will need if you plan on continuing to use your Jails long term.
Note: FreeBSD defines network interfaces by their device name or module name. Replace hme0 with your interface name as required.
Temporary Network Alias
To create temporary network aliases for the three Jails you would run these commands (replacing each IP as needed):
ifconfig hme0 alias 192.168.0.100 netmask 255.255.255.255
ifconfig hme0 alias 192.168.0.101 netmask 255.255.255.255
ifconfig hme0 alias 192.168.0.102 netmask 255.255.255.255
Persistent Network Alias
To create persistent network aliases (aliases that will persist across reboots) you would add the following to your /etc/rc.conf file (replacing your IP as needed):
Creating a Jail environment
Once you have activated your network aliases and the third and final configuration requirement is met we’re ready to create these Jails. You can create a Jail environment using the command below. Repeat for each Jail, replacing jailname and jailip as needed:
ezjail-admin create jailname jailip
In this situation we would have run the following commands:
ezjail-admin create larry 192.168.0.100
ezjail-admin create moe 192.168.0.101
ezjail-admin create curly 192.168.0.102
You will see a bunch of output on your screen. This is normal. The output shows that files are being put into place and underlying configuration is happening. Remember, without the ezjail-admin tool you’d need to do that configuration by hand. No thanks!
Your Jail environments are now ready to use! Wasn’t that easy! To move from you host system to your Jail environment simply use the command:
ezjail-admin console jailname
This command will give you a console connection into the Jail environment. It will act just as if you had sat down and logged into the machine (although no login credentials are required). You should now be within one of your Jails, logged in as root, with a base FreeBSD system. No ports are installed. Nothing is configured. None of the host customizations are adopted. You have a pristine, minimal FreeBSD installation to begin building your services.
Configure and activate SSH
Let’s configure a service and make this Jail more accessible. First, SSH: SSH is part of the base FreeBSD installation so all we need to do is configure and activate the service. It should work out of the box, but it can’t hurt to take a look at the configuration for the SSH daemon, located in /etc/ssh/sshd_config.
You may want to update the following lines:
For this example we’ll change the port to 2200 and the ListenAddress to 192.168.0.100.
Update the Jail environment to launch the SSH daemon at startup by adding the following line to your /etc/rc.conf:
Finally, start the service manually by running:
If you now logout of your Jail (type “exit”) and take a look at your host system using netstat you should find that it is listening on 192.168.0.100:2200—the host address and port (assuming ssh is configured on the host system). You can find this information using:
netstat -nat | less