Using jails in FreeBSD 10

Introduction

Lately, containers have become popular in the GNU/Linux world. However, FreeBSD has had this functionality for ages, called jails.

Configuring FreeBSD jails

By default, FreeBSD jails do not have internet access, and it's up to the administrator to configure how a jail should connect to the internet. We'll assume a setup where we share the IP address of the host. When using IPv6, it's possible to assign multiple IPv6 addresses to the host, and assign jails one dedicated address each. Check jail(1) and jail.conf(5) for more information. Write the /etc/jail.conf file:

/etc/jail.conf

path = "/usr/jails/$name"; host.hostname = "$name.fyrkat.no"; mount.devfs; allow.raw_sockets; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown";

Install FreeBSD in a jail

According to jail(8), we should install FreeBSD by compiling sources from /usr/src, but this would take a long time and requires that we have sources installed. A better solution would be to use the procedure lined out in the FreeBSD handbook on jails, which suggests we download the FreeBSD iso and extract the relevant portions. However, that still requires that we download the ISO and mount it. In this tutorial, we'll just download the relevant files from the closest FreeBSD mirror.

 

sh
export URL_BASE=http://ftp.freebsd.org/pub/FreeBSD/releases/`uname -p`/`uname -r | sed -e 's/-p[0-9]$//'`
mkdir -p /usr/jails
cd /usr/jails
wget $URL_BASE/base.txz $URL_BASE/ports.txz
--2015-11-19 15:14:23--  http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz
Resolving ftp.freebsd.org (ftp.freebsd.org)... 2001:6c8:130:800::4, 193.162.146.4
Connecting to ftp.freebsd.org (ftp.freebsd.org)|2001:6c8:130:800::4|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 67410700 (64M) [application/octet-stream]
Saving to: 'base.txz'

base.txz                      100%[===================================================>]  64.29M  11.3MB/s   in 6.5s

2015-11-19 15:14:32 (9.96 MB/s) - 'base.txz' saved [67410700/67410700]

--2015-11-19 15:14:32--  http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/ports.txz
Reusing existing connection to [ftp.freebsd.org]:80.
HTTP request sent, awaiting response... 200 OK
Length: 39402500 (38M) [application/octet-stream]
Saving to: 'ports.txz'

ports.txz                     100%[===================================================>]  37.58M  12.2MB/s   in 3.1s

2015-11-19 15:14:35 (12.2 MB/s) - 'ports.txz' saved [39402500/39402500]

FINISHED --2015-11-19 15:14:35--
Total wall clock time: 12s
Downloaded: 2 files, 102M in 9.5s (10.7 MB/s)

The following shell code will then install a jail named myjail.

sh
export JAIL=myjail
mkdir -p /usr/jails/$JAIL
cd /usr/jails
tar -xf base.txz -C /usr/jails/$JAIL
grep ^$JAIL /etc/jail.conf || echo $JAIL '{}' >> /etc/jail.conf
cp /etc/resolv.conf /usr/jails/$JAIL/etc/resolv.conf

Starting and stopping jails

Now we have a jail set up, we just need to start it. Run:

 

jail -c myjail
myjail: created
/etc/rc: WARNING: $hostname is not set -- see rc.conf(5).
Creating and/or trimming log files.
Starting syslogd.
syslogd: child pid 12303 exited with return code 1
/etc/rc: WARNING: failed to start syslogd
ELF ldconfig path: /lib /usr/lib /usr/lib/compat
32-bit compatibility ldconfig path: /usr/lib32
Clearing /tmp (X related).
Updating motd:.
Starting sendmail_submit.
554 5.3.0 host "localhost" unknown: Protocol not supported
/etc/rc: WARNING: failed to start sendmail_submit
Starting sendmail_msp_queue.
Starting cron.

Thu Nov 19 14:05:57 UTC 2015

Now we have a running jail! To see a list of running jails, run:

jls
   JID  IP Address      Hostname                      Path
    id  -                                             /usr/jails/myjail

If we want to start a shell (or any other command) in the jail, run:

jexec myjail /bin/sh

To shut down the jail, run:

jail -r myjail
Nov 18 15:51:44  syslogd: exiting on signal 15
myjail: removed

Automatically starting and stopping jails on boot and shutdown

In order to start jails automatically together with the host, edit rc.conf.

/etc/rc.conf

jail_enable="YES" # Set to NO to disable starting of any jails jail_list="myjail" # Space separated list of names of jails

Networking

There are multiple options available for networking. By default, a jail won't have any network connectivity. This is typically not what you want. Edit the jail.conf(5) file and update the settings for the jail. Simply speaking, there are three ways to configure networking in a jail.

(1) Share the IP-address of the host machine, this will work if you don't try to run services on the same port as another jail or the host. This may be the preferred way of doing things on a legacy IPv4-only network.

/etc/jail.conf

myjail { ip6 = "inherit"; ip4 = "inherit"; }

(2) Claim one or more IP-adresses available to the host, this typically requires IP aliases or multiple network interfaces. Note that IP addresses you delegate this way must already be available to the host, you do this by editing rc.conf on the host.

/etc/rc.conf

ifconfig_em0_alias0="inet6 2001:db8::2 prefixlen 64" ifconfig_em0_alias1="192.0.2.3 netmask 255.255.255.0"

/etc/jail.conf

myjail { ip6.addr = "2001:db8::2"; ip4.addr = "192.0.2.3"; }

(3) *Not in the default kernel* Give the jail its own virtual network stack through vnet, this requires a specially compiled FreeBSD kernel. This gives the jail a tap interface that is connected to the host. This makes it possible to NAT or bridge the jail, without making the jail's IP address available to the host.

/etc/jail.conf

myjail { vnet; }

Pitfalls

  1. When you start a jail with an ip4.addr or ip6.addr configured, the IP address must be assigned to a network interface. Run service netif restart to apply changes made in rc.conf.
  2. Services on the host that bind :: or 0.0.0.0 will listen on IP addresses assigned to jails as well if the jail doesn't listen on the same port. This can cause unexpected surprises when the host has an SSH server running, and the jail does not. The solution is to run as few services on the host as possible, and the services that do run on the host should listen on the IP address of the host only.

Additional security

Even though jails provide some kind of security, processes still run as root. In order to add some security, it is possible to set a securelevel for a jail that is equal or higher than the host of the jail. In order to set a securelevel, add securelevel = "0" to jail.conf. Replace 0 with the securelevel of your choice. See security(7), securing the kernel, for which security levels are available.

See also