You may have found many great resources on how to set up jails on latest FreeBSD, however there is scant information on how to go about creating a barebones jail with nothing but the one process that you want to isolate.
I was curious if I could contain a statically compiled web server that I wrote while learning Rust all by itself in a jail instead of having a full userland.
The benefits are:
- Storage space requirement is trivial: 5MB
- No need to update the jail separately since there is only one additional binary to daemonize the web app
- Updating the web app is as simple as stopping the jail, replacing the binary and restarting, with a shell script on the host, that's fast.
- If an intruder does manage to break in, there is no shell, utility programs or interpreters to leverage
- Working FreeBSD 12.1 machine (this should work on older versions, but I have not tested)
- Working internet connection to download a package (daemonize)
- Static-linked binary web app (with Rust, use
cargo build --release
) - A bit of patience
First, create directories for the jail.
mkdir -p /usr/local/jail/www/{app,dev,lib,libexec,var}
mkdir -p /usr/local/jail/www/var/{log,run}
This will create the following tree structure:
[/usr/local/jail/www]# tree
.
├── app
├── dev
├── lib
├── libexec
└── var
├── log
└── run
6 directories, 0 files
Now copy a few required binaries to the jail:
cp /libexec/ld-elf.so.1 /usr/local/jail/www/libexec/
cp /lib/{libc.so.7,libgcc_s.so.1,libm.so.5,libthr.so.3} /usr/local/jail/www/lib/
The directory tree should look like this:
[/usr/local/jail/www]# tree
.
├── app
├── dev
├── lib
│ ├── libc.so.7
│ ├── libgcc_s.so.1
│ ├── libm.so.5
│ └── libthr.so.3
├── libexec
│ └── ld-elf.so.1
└── var
├── log
└── run
7 directories, 5 files
Install the package daemonize
on host:
pkg install daemonize
Copy the daemonize binary to jail:
cp /usr/local/bin/daemonize /usr/local/jail/www/app/
Now copy your static-linked web app to jail.
Here I'm copying the Rust web app created using Rocket.rs
and compiled for release (cargo build --release
)
cp /home/hiway/source/webapp/target/release/webapp /usr/local/jail/www/app/
The directory tree should look like this now:
[/usr/local/jail/www]# tree
.
├── app
│ ├── daemonize
│ └── webapp
├── dev
├── lib
│ ├── libc.so.7
│ ├── libgcc_s.so.1
│ ├── libm.so.5
│ └── libthr.so.3
├── libexec
│ └── ld-elf.so.1
└── var
├── log
└── run
Next, we will set up jails service.
Edit or create /etc/jail.conf
using your preferred text editor and append the following to it:
Remember to review the values such as ip4.addr
and replace with appropriate values for the interface, ip address and subnet.
www {
host.hostname = "www";
ip4.addr = "wlan0|192.168.0.99/24";
path = "/usr/local/jail/www";
mount.devfs;
exec.start = "/app/daemonize -v -a \
-o /var/log/www.stdout \
-e /var/log/www.stderr \
-p /var/run/www.pid /app/webapp";
exec.stop = "";
}
Enable jail service:
sysrc jail_enable=YES
And finally, start the jail:
service jail start www
Visit http://192.168.0.99:8000/
from your browser and verify that it works.
mostly works on 14.1. Newly required:
Do note that this won't work if you need an init process, but this guide doesn't claim to in the first place. It's just true that many programs that are not built to run in an environment this minimal can rely on an init process to come reap grandchildren processes