How to set up a basic chroot jail on Debian Buster – Part I: Nginx
Table of Contents
Chroot provides an extra layer for security. However, care must be taken when setting up the environment to avoid unexpected results. Arch Wiki has a page that contains detailed steps and explanations, which should work on Debian as well with a few tweaks. Here we assumes Nginx is already installed using apt
.
Initiate directory structure
The chroot jail is created at JAIL=/opt/chroot
.
mkdir $JAIL && cd $JAIL
mkdir {dev,etc,run,tmp,usr,var}
mkdir usr/{sbin,lib,lib64,share}
mkdir var/{www,log,lib}
mkdir usr/lib/x86_64-linux-gnu
mkdir var/{log,lib}/nginx
ln -s usr/sbin sbin
ln -s usr/lib lib
ln -s usr/lib64 lib64
Create device nodes
Nginx requires /dev/null
, /dev/random
and /dev/urandom
.
cd $JAIL/dev
mknod -m 0666 null c 1 3
mknod -m 0666 random c 1 8
mknod -m 0444 urandom c 1 9
For some unprivileged containers that disallow mknod
execution, consider using mount --bind
as an alternative.
cd $JAIL/dev
touch null random urandom
mount --bind /dev/null null
mount --bind /dev/random random
mount --bind /dev/urandom urandom
Copy files
Copy module configurations:
cp -r /usr/share/nginx $JAIL/usr/share
cp -r /lib/nginx $JAIL/lib
Copy web contents:
cp -r /var/www/* $JAIL/var/www
Copy configuration files:
cp -rfvL /etc/nginx $JAIL/etc
You may want to restore symlinks in $JAIL/etc/nginx/modules-enabled
.
Copy the executable:
cp /sbin/nginx $JAIL/sbin
Copy dylibs:
cp $(ldd /sbin/nginx | grep /lib/ | sed -sre 's/(.+)(\/lib\/x86_64-linux-gnu\/\S+).+/\2/g') $JAIL/lib/x86_64-linux-gnu
cp /lib64/ld-linux-x86-64.so.2 $JAIL/lib64
Copy system files:
cp /lib/x86_64-linux-gnu/libnss_* $JAIL/lib/x86_64-linux-gnu
cp -rfvL /etc/{services,localtime,nsswitch.conf,nscd.conf,protocols,hosts,ld.so.cache,ld.so.conf,resolv.conf,host.conf} $JAIL/etc
Fake user database
cat /etc/passwd | grep www-data > $JAIL/etc/passwd
cat /etc/passwd | grep nobody >> $JAIL/etc/passwd
cat /etc/group | grep www-data > $JAIL/etc/group
cat /etc/group | grep nogroup >> $JAIL/etc/group
cat /etc/shadow | grep www-data > $JAIL/etc/shadow
cat /etc/shadow | grep nobody >> $JAIL/etc/shadow
cat /etc/gshadow | grep www-data > $JAIL/etc/gshadow
cat /etc/gshadow | grep nogroup >> $JAIL/etc/gshadow
Mount temporary filesystem
mount -t tmpfs none $JAIL/run -o 'noexec,nodev,size=1M'
mount -t tmpfs none $JAIL/tmp -o 'noexec,nodev,size=10M'
cat >> /etc/fstab << EOF
> tmpfs /opt/chroot/run tmpfs rw,noexec,nodev,relatime,size=1024k 0 0
> tmpfs /opt/chroot/tmp tmpfs rw,noexec,nodev,relatime,size=10240k 0 0
> EOF
Restrict file permissions
chown -R root:root $JAIL
chown -R www-data:www-data $JAIL/var/www
chown -R www-data:www-data $JAIL/etc/nginx
chown -R www-data:www-data $JAIL/var/log/nginx
chown -R www-data:www-data $JAIL/var/lib/nginx
find $JAIL -user root -type d -print | xargs chmod -rw
find $JAIL -user www-data -print | xargs chmod o-rwx
chmod +rw $JAIL/{run,tmp}
Edit configurations
Add systemd chroot support:
systemctl edit nginx
systemctl daemon-reload
[Service]
PIDFile=/opt/chroot/run/nginx.pid
RootDirectory=/opt/chroot
User=www-data
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
ExecStop=/sbin/nginx -g 'daemon on; master_process on;' -s quit
Comment unnecessary lines in $JAIL/etc/nginx.conf
:
# already running as www-data
#user www-data;
# external modules bring tons of dependencies
#include /etc/nginx/modules-enabled/*.conf;
Finish
systemctl restart nginx