Jails

FreeBSD jail(8) provides lightweight, kernel-level containers for the secure isolation of one or more processes up to a complete userland.

Jails were introduced by Poul-Henning Kamp in March 2000 with FreeBSD 4.0-RELEASE.

Additional Resources

Jail-specific and Jail-aware Utilities

Feature Requests

Feature requests, directly within jail(8) or supporting resources:

VNET-based networking for Jails

Configuration

The VNET is set up using an if_epair(4) interface bridged with the actual network interface, in my case re0. Just like if_tap(4) interfaces, epairs can be used by one jail at a time, so if you need to run more than one jail at the same time, you have to make more epairs.

If you're using tap interfaces for bhyve VMs, you can just addm them into the bridge.

Add the following lines to /etc/rc.conf:

cloned_interfaces="bridge0"
ifconfig_bridge0="addm re0 up"

Add or edit the kld_list parameter to add the following module in /etc/rc.conf:

kld_list="if_bridge if_epair"

Apply changes:

# service netif restart && service routing restart

The jail needs to inherit /dev/bpf* from the host in order for networking to work at all. Make a new /etc/devfs.rules ruleset:

[devfsrules_jails=5]
add include $devfsrules_hide_all
add include $devfsrules_unhide_basic
add include $devfsrules_unhide_login
add path 'bpf*' unhide

Restart devfs(8):

# service devfs restart

We'll name this jail foo and give it the other end of the epair as its network interface. Its IP address will be acquired using DHCP. The reason I'm manually calling dhclient(8) is because adding ifconfig_epair0b="DHCP" in the jail's /etc/rc.conf doesn't work. Options are detailed in jail.conf(5).

/etc/jail.conf:

path = "/usr/local/jail/$name";
host.hostname="$name";

exec.clean;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
allow.mount;
allow.raw_sockets = 1;
mount.devfs;
devfs_ruleset="5";
vnet;
sysvmsg=new;
sysvsem=new;
sysvshm=new;

foo {
        vnet.interface = "epair0b";
        exec.start += "dhclient epair0b";
}

Adding additional jails

There are a few things that should always be kept in mind:

Installation

# mkdir -p /usr/local/jail/foo
# bsdinstall jail /usr/local/jail/foo
...
# ifconfig epair0 create
# ifconfig bridge0 addm epair0a
# ifconfig epair0a up
# service jail start foo

Test to see if the jail has networking:

# jexec foo ping google.com

On jail shutdown, destroy the epair:

# service jail onestop foo
# ifconfig epair0a destroy

Delete jail

Deleting jails isn't as straight forward, so I'm leaving this here as well:

# service jail stop foo
# chflags -R noschg /usr/local/jail/foo
# rm -rf /usr/local/jail/foo

Netgraph-based networking for jails

Introduction

There are three ways to do networking with jails: (i) using IP addresses (aliases) from the host, (ii) using if_bridge(4) and epair(4) interfaces, and (iii) using netgraph. I will start this how-to with the third method as the second method has already been explained by Mason Loring Bliss.

Netgraph Terminology

Node
Any object that can connect to another object. This can be a bridge, a virtual interface, but also a VLAN interface or a BPF object.
Edge
The connection between two nodes. You could consider it to be a virtual network cable.
Hook

In netgraph, edges do not really exist per se. Instead, an edge is simply an association of two hooks, one from each node. A node's hooks define how that node can be connected. For a bridge node, the hooks are the virtual interfaces, though for a virtual interface node, hooks can be each protocol supported by that interface.

Path

Every netgraph node is addressable via an ASCII string called a node address or path. Many nodes have names. When a node has a name, it can always be addressed usingthe absolute address consisting of the name followed by a colon. If a node does not have a name, you can construct one from the node's unique ID number by enclosing the number in square brackets. Relative addressing is also possible when two nodes are indirectly connected. A relative address uses the names of consecutive hooks on the path from the source node to the target node. Relative and absolute addressing can be combined.

This is quite confusing. See the example at https://people.freebsd.org/~julian/netgraph.html.

Let's start off with a small network consisting of two jails, called "test1" and "test2", which are bridged to an new, virtual interface on the host machine. We thus need three new virtual interfaces. We will use ngctl to manage all netgraph nodes, hooks, and edges. This tool can be used interactively or you can supply the command on the command line. Below we will use it interactively. Note that this command must be run as the root user.

# ngctl

mkpeer eiface ether ether
mkpeer eiface ether ether
mkpeer eiface ether ether
name ngeth0: ng_host
name ngeth1: ng_test1
name ngeth2: ng_test2

We create three interfaces of type eiface as we need Ethernet interfaces (as opposed to L3 interfaces when using type iface). The man page state they are named ngeth0, etc. We rename them to indicate their purpose.

Note that when referencing a node name, we must append it with a colon. That is because we're specifying a path, not just a node.

Next we need to bridge these interfaces together. We can either create the bridge first and then connect it to the three interfaces, or while creating the bridge, we can already connect it to an interface.

/*
 * OPTION A:
 * To only create the bridge but not connect it to any existing nodes
 */
mkpeer bridge link0 link0

/*
 * OPTION B:
 * Create a new node of type bridge and connect it to the
 * path 'ng_host:'.  Use its hook called 'ether' to connect it to the
 * hook 'link0' of the new node (the bridge).
 */
mkpeer ng_host: bridge ether link0

/*
 * As opposed to the Ethernet interfaces, a bridge does not have a
 * name by default. So we name it here.
 */
name [1e]: br0

/*
 * Now connect the nodes together.  The first connection is only needed
 * when option A was used.
 */
connect br0: ng_host: link0 ether
connect br0: ng_test1: link1 ether
connect br0: ng_test2: link2 ether

The above configuration is pretty straightforward, the exception being the name command. Since the bridge does not have a name, we can't use it to construct a path. Instead we must use its unique ID (between brackets). To determine this ID, we need the list command which I ommitted from the configuration above. Let's show it here.

+ list
There are 6 total nodes:
  Name: ng_host         Type: eiface          ID: 00000007   Num hooks: 1
  Name: ng_test1        Type: eiface          ID: 00000009   Num hooks: 0
  Name: ngctl85802      Type: socket          ID: 0000002b   Num hooks: 0
  Name: <unnamed>       Type: bridge          ID: 0000001e   Num hooks: 1
  Name: ng_test2        Type: eiface          ID: 0000000e   Num hooks: 0
+

The above output shows the unique ID for the bridge (preceding zeros can be ommitted) as well as the number of hooks used, i.e. connections made. I thus created the bridge by directly connecting it to the ng_host interface.

Configuring the jails

I assume you know how to setup a jail, i.e. create a base jail, clone it, etc. If not, please read the Jails chapter of the FreeBSD Handbook.

The below configuration only includes the networking-specific configuration for the two jails. Although shown per jail, you can easily move these two lines to the default configuration using the variable $name to customize the interface name.

test1 {
   vnet;
   vnet.interface = ng_test1;
}
test2 {
   vnet;
   vnet.interface = ng_test2;
}

Once the jails have been started, you can manually configure IP addresses on their interfaces, as well as on the host interface ng_host.

NAT to be covered in the future.

Additional Netgraph resources

Jail Management Tools

AppJail
Simple and easy-to-use tool for creating portable jails.

sysutils/appjail

sysutils/appjail-devel

Bastille
Pure shell system for automating deployment and management of containerized applications in jails

sysutils/bastille

BSDploy (unmaintained)
Container management and orchestration for FreeBSD jails using ansible

sysutils/bsdploy

cbsd
FreeBSD jail and bhyve management utility

sysutils/cbsd

crate
An application containerizer utilizing jails

sysutils/crate

ezjail
A framework to easily create, manipulate and run FreeBSD jails

sysutils/ezjail

focker

A jail-based image orchestration tool in the vein of Docker

sysutils/py-focker

iocage
Utility for managing jails

sysutils/iocage

iocell

iocage fork focused on supporting classic iocage experience and adding fixes and features requested by the iocage users

sysutils/iocell

jadm
FreeBSD jail framework with zfs, vnet and jail.conf support

sysutils/jadm

jailadmin
A system for managing a set of named jails

sysutils/jailadmin

jailaudit
Script for generating portaudit reports for jails

ports-mgmt/jailaudit

jailctl (unmaintained)
Jail management tool

sysutils/jailctl

jailer (unmaintained)
Manage FreeBSD jail startup, shutdown and console

sysutils/jailer (This port expired on: 2014-03-10)

jailme (unmaintained)
A setuid version of jexec to allow normal users access to jails

sysutils/jailme

jailrc
Improved jail startup/shutdown script

sysutils/jailrc

jailutils
Several utilities for managing jails

sysutils/jailutils

jest
REST API for creating and managing jails

sysutils/jest

jkill
Shutdowns a running jail and all its processes

sysutils/jkill

jps
Wrapper to ps(1) that maps pids to jails

sysutils/jps

jruls
A top-alike utility to display and update FreeBSD jails resource usage

sysutils/jruls

jtop
Wrapper to top(1) that maps pids to jails

sysutils/jtop

mkjail
Easy jail creation, updates and upgrades

sysutils/mkjail

mod_jail (unmaintained)
Apache 1.3.x/2.0.xx module to enable an easy alternative to mod_chroot

www/mod_jail (This port expired on: 2017-04-30)

p5-BSD-Jail-Object
An object oriented perl interface to jail(2)

sysutils/p5-BSD-Jail-Object

ploy
Command-line tool to provision, manage, and control servers, including jails

sysutils/py-ploy

pot
Container framework for FreeBSD, based on jails, ZFS and pf

sysutils/pot

qjail
Utility to deploy large number of jails quickly

sysutils/qjail

quickjail
utility to create transient single-command jails

sysutils/quickjail

runj
Proof-of-concept OCI-compatible runtime for FreeBSD jails

sysutils/runj

Jails (last edited 2024-10-30T22:08:16+0000 by RafaelGrether)