Jailing an SSH User on Linux

Jailing an SSH User on Linux
Jérémie Kassianoff
February 23, 2014
8 min read

Understand the chroot/jail technique on Linux. Restricted access for your SSH users. Use Jailkit or the fuschlberger script!

Real-world use case

You need to restrict an SSH user to a specific scope: here's how to set up a chroot/jail on Linux.

Jailing a user

Shared projects can sometimes lead to giving access to a production server.
It's difficult to give full access to the system to an external company (confidentiality/security).
To address this issue, there's chroot/jail, or jailing a user inside a folder.
The complete view of the server's directory tree will no longer be available to this user.
Jailing them provides:

  • Increased flexibility.
  • Additional security.
  • Easier access provisioning.

Creating a closed environment

Understanding the general steps in creating a chroot/jail is important:

  1. Creating a user on the system.
  2. Creating the jail directory's structure.
  3. Adding a command interpreter.
  4. Mounting devices (optional).
  5. Modifying certain "/etc/" files.
  6. Creating a so-called wrapper function.
  7. Adding file permissions.
  8. Adding extra commands.

For more information on step-by-step creation of a "chroot/jail" environment, see léa-linux.
This method is fairly long, so we'll instead use existing scripts.
The scripts we'll use are Jailkit and the fuschlberger script on Debian 7 x64.

The first is a turnkey script that's still actively developed and more advanced, while the second is aging but works just as well, though with more difficulties on the 64-bit version.
More information on the official website of jailkit as well as the fuschlberger website.

The Jailkit script

Jailkit is a maintained script that lets you automate building a jail.
We can add one or more users to it in order to restrict them.

Download the script with "wget":

bash
wget http://olivier.sessink.nl/jailkit/jailkit-2.17.tar.gz

Extract the file:

bash
tar xvzf jailkit-2.17.tar.gz

Head to the folder:

bash
cd jailkit-2.17

Run the following command:

bash
./debian/rules binary
=> make[1]: leaving directory "/root/jailkit-2.17"

Exit the current directory:

bash
cd ..

Start installing Jailkit:

bash
dpkg -i jailkit_2.17-1_amd64.deb

Notice that new commands are now available: try running: "jk_"

bash
jk_addjailuser   jk_chrootlaunch  jk_cp            jk_jailuser      jk_lsh           jk_uchroot       
jk_check         jk_chrootsh      jk_init          jk_list          jk_socketd       jk_update

Create the jail directory:

bash
mkdir /home/jail/

We need to give all permissions to "root":

bash
chown root:root /home/jail/

Add programs to the jail:

bash
jk_init -v /home/jail netutils basicshell jk_lsh ssh sftp editors

To add other programs, simply edit the following configuration file:

bash
nano /etc/jailkit/jk_init.ini

Copying libraries is done with the "jk_cp" command, e.g. with "mysql":

bash
jk_cp -j /home/jail/ /usr/bin/mysql

For information, here's how to display a program's libraries:

bash
ldd /usr/bin/mysql

If you want to use mysql inside your jail:

bash
mount --bind /var/run/mysqld/ /your/jail/var/run/mysqld/

Create the user who will be "chrooted" in their jail:

bash
adduser jeremie
=>Adding user `jeremie' ...
Adding new group `jeremie' (1001) ...
Adding new user `jeremie' (1001) with group `jeremie' ...
Creating home directory `/home/jeremie'...
Copying files from `/etc/skel'...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for jeremie
Enter the new value, or press Enter for the default
        Full Name []: Jérémie Kassianoff
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
chfn : name contains non-ASCII characters: Jérémie Kassianoff
Is the information correct? [Y/n]Y

We add the user to the jail with the following command:

bash
jk_jailuser -m -j /home/jail/ jeremie

Edit the file of existing users on the "jail" system:

bash
nano /home/jail/etc/passwd

Find your user and change your "shell":

bash
jeremie:x:1001:1001:,,,:/home/jeremie:/bin/bash

You can now log in as your user:

bash
su - jeremie

Show the jail's root:

bash
ls /
bin  dev  etc  home  lib  lib64  usr

The jailkit introduction is complete.

The fuschlberger script

The fuschlberger script is fairly old (2008) but it still works very well.
We'll get it running on Debian 7 64-bit.

Before anything else, make sure you have the following packages installed:

bash
debianutils coreutils

Download the script with "wget":

bash
wget http://www.fuschlberger.net/programs/ssh-scp-sftp-chroot-jail/make_chroot_jail.sh

Make the script executable:

bash
chmod 770 make_chroot_jail.sh

Run the script (simplified version):

bash
make_chroot_jail.sh jeremie

By default the jail will be located at "/home/jail", if you want to change the directory:

bash
make_chroot_jail.sh jeremie [/path/shell] [/path/jail]

If you run the script, you'll most certainly get an error on the 64-bit version.
Now we're going to start changing certain values in the script.

Errors on Debian 7 X64

The first time you run the script (x64) you probably saw errors appear.
To fix the first error (line 406 & 407), you need to edit the fuschlberger script:

bash
nano make_chroot_jail.sh

Then find the following two lines:

bash
TMPFILE1=`mktemp` &> /dev/null ||  TMPFILE1="${HOME}/ldlist"; if [ -x ${TMPFILE1} ]; then mv ${TMPFILE1} ${TMPFILE1}.bak;fi
TMPFILE2=`mktemp` &> /dev/null ||  TMPFILE2="${HOME}/ldlist2"; if [ -x ${TMPFILE2} ]; then mv ${TMPFILE2} ${TMPFILE2}.bak;fi

You need to remove "/dev/null" like this:

bash
TMPFILE1=`mktemp` ||  TMPFILE1="${HOME}/ldlist"; if [ -x ${TMPFILE1} ]; then mv ${TMPFILE1} ${TMPFILE1}.bak;fi
TMPFILE2=`mktemp` ||  TMPFILE2="${HOME}/ldlist2"; if [ -x ${TMPFILE2} ]; then mv ${TMPFILE2} ${TMPFILE2}.bak;fi

The second problem is in the library paths:

bash
elif [ "$DISTRO" = DEBIAN ]; then
  cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
else
  cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
fi

We end up with paths for the x86 version, so we need to adapt them to our x64 system:

bash
elif [ "$DISTRO" = DEBIAN ]; then
  cp /lib/x86_64-linux-gnu/libnss_compat.so.2 /lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-$
else
  cp /lib/x86_64-linux-gnu/libnss_compat.so.2 /lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-$
fi

Once the issues are fixed, rerun the script with the command:

bash
 make_chroot_jail.sh jeremie

Then, the command's output will show:

bash
 Release: 2008-04-26

Am I root?
  OK
Checking distribution...
  Supported Distribution found
  System is running Debian Linux
Checking for which...
  OK
Checking for chroot...
  OK
Checking for sudo...
  OK
Checking for dirname...
  OK
Checking for awk...
  OK

Subsystem sftp /usr/lib/openssh/sftp-server

-----------------------------
The file /bin/chroot-shell exists.
Probably it was created by this script.

Are you sure you want to overwrite it?
(you want to say yes for example if you are running the script for the second
time when adding more than one account to the jail)
(yes/no) -> yes

Modifying /etc/sudoers
Adding User "jeremie" to system
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

Adding User jeremie to jail
Copying necessary library-files to jail (may take some time)
Copying files from /etc/pam.d/ to jail
Copying PAM-Modules to jail

If you browse the jail folder:

bash
ls -al /home/jail

You'll see the work done by the fuschlberger script.
Try logging in with the user you previously created:

bash
su - jeremie

"su: module is unknown" error:

bash
 su: Module is unknown

The solution I found is to edit the chroot-shell file:

bash
nano /bin/chroot-shell

Initially you'll find this inside:

bash
#!/bin/bash 
/usr/bin/sudo /usr/sbin/chroot /home/jail /bin/su - $USER "$@"

The change to make:

bash
#!/bin/bash
sudo /usr/sbin/chroot /home/jail /bin/bash

Then you need to rerun the command:

bash
su - jeremie

You should now be logged in with no errors, and you're indeed inside your jail.
However, you have a restricted list of commands, to add more: edit the script!

bash
nano /usr/local/sbin make_chroot_jail.sh

Search for the "APPS" line with "ctrl + w" and add the path of the commands you want.

bash
elif [ "$DISTRO" = DEBIAN ]; then
  APPS="/bin/bash /bin/crontab /bin/vim /bin/mysql /bin/hg /bin/hg-ssh /usr/bin/clear /usr/bin/ncurses5-config /bin/nano /bin/cp /usr/bin/ /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/ping  /bin/su /usr/bin/groups /usr/bin/id /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"

Then, you need to update your jail with the script:

bash
make_chroot_jail.sh update

Also, if you want to resolve domain names you'll need to add the DNS library:

bash
cp /lib/x86_64-linux-gnu/libnss_dns.so.2 /home/jail/lib

This script is a bit dated but makes for a good base to get started with jail/chroot.

Conclusion

I've compared here two methods for jailing an SSH user on Linux: the Jailkit script, more recent and maintained, and the fuschlberger script, older but still functional with a few adjustments for the 64-bit version. These chroot/jail techniques let you provide restricted access to a production server without exposing its entire directory tree, which strengthens security and confidentiality during external collaborations. One point to watch: the list of commands available inside the jail should be adjusted sparingly so as not to recreate an environment that's too open. Personally, I stopped there and didn't look into the other possible options.
You now know how to use these two scripts! Share your feedback in the comments section.