Originally published March 25, 2019 @ 5:09 pm

Just a quick collection of notes on – rather than a definitive guide to – setting up an SSH chroot jail on RHEL 6. The same should work on RHEL 7 and unrelated flavors. For the most part.

Similar to FTP, the SSH chroot jail locks the user in his home directory, while allowing access to a localized selection of executables and libraries.

Build the jail

These are some preliminary steps to configure the jail base directory.

d=/var/jail
mkdir -p ${d}/{dev,etc,lib,lib64,usr,bin}
mkdir -p ${d}/usr/bin
chown root.root ${d}
mknod -m 666 ${d}/dev/null c 1 3

for i in ld.so.cache ld.so.conf nsswitch.conf hosts; do
/bin/cp -p /etc/${i} ${d}/etc/
done

Configure l2chroot script

The l2chroot script allows you to create localized copies of system binaries with all the required libraries. In the example below we use l2chroot top copy ls and bash executables and related libraries to the jail base directory.

d=/var/jail
wget -O /sbin/l2chroot http://www.cyberciti.biz/files/lighttpd/l2chroot.txt
chmod +x /sbin/l2chroot
sed -i "s@/webroot@$d@g" /sbin/l2chroot
l2chroot /bin/ls
l2chroot /bin/bash

Configure SSHd

Here we add a match stanza to the sshd_config to identify the users that should be jailed. In this example all users in the users, GID 100 group will be jailed, except a user named jdoe01.

u=jdoe01
g=users
d=/var/jail

cat << EOF >> /etc/ssh/sshd_config
Match group ${g} User !${u}
  ChrootDirectory ${d}/
  X11Forwarding no
  AllowTcpForwarding no
EOF
/sbin/service sshd reload

Create user jail cells

We need to create a home directory under /var/jail for every user in the primary users group. Here I am also copying the contents of the original user home directories to the jail ones, so the first step is to make sure there’s enough disk space.

d=/var/jail
g=users
gid=$(awk -v g="$g" -F: '$1 == g {print $3}' /etc/group)
awk -F: -v gid="$gid" '($4 == gid && $1 !~ /^#/)  {print $1,$6,$7}' /etc/passwd | sort -u | while read -r u h s; do
  mkdir -p ${d}${h}
  rsync -avKx /etc/skel/ ${d}${h}/
  rsync -avKx ${h}/ ${d}${h}/
  chown -R ${u}:${gid} ${d}${h}
done

Going the extra mile

The setup above is minimally functional: user will be able to log in, get bash shell, and enjoy running the ls command. However, this is unlikely to impress anyone. We need more binaries available to the users.

One way to go is to use the l2chroot command more extensively. In the example below I copy all binaries from /bin and /usr/bin to the jail base directory. Once again, be mindful of available disk space.

for i in $(find /bin/ -maxdepth 1 -mindepth 1 -type f -executable); do l2chroot $i; done
for i in $(find /usr/bin/ -maxdepth 1 -mindepth 1 -type f -executable); do l2chroot $i; done

If you want sudo to work, you would need to do a bit more work, as shown below.

d=/var/jail
rsync -avKx /root ${d}
cd /etc/.git && git count-objects -v && git gc
rsync -avKx /etc/ ${d}/etc/
rsync -avKx /lib64/ --include 'libnss*' /var/jail/lib64/
rsync -avKx --exclude='usermin*' --exclude='webmin*' /usr/libexec /var/jail/usr/