SSH and SFTP Chroot Jail

09
Jan
2014

SSH and SFTP Chroot Jail

SSH and SFTP Chroot Jail
Photo by Andrea Schaffer

For a little while now I've wanted to be able to chroot both SFTP and SHH accounts on one of my multi-user VPSs.

SFTP on its own is not so difficult. OpenSSH 4.9p1 and above includes the ChrootDirectory directive. And an SFTP chroot is a little more forgiving in so far as it doesn't actually require any supporting system or userpsace services (a shell, ls, cp, etc.), which is why you often see ChrootDirectory accompanied with ForceCommand internal-sftp which will prevent SSH access altogether.

What I'd like to do is create a restricted environment for both SSH and SFTP.

I spent a little while looking at a very interesting project from Olivier Sessink called Jailkit. Jailkit has most of what I was looking for but, it has quite a few moving parts, including the need to replace a users shell with a special Jailkit shim that hands over to Jailkit. This is okay but it means changes to passwd are required, and editing your /etc/ssh/sshd_config to use Subsystem sftp /usr/lib/openssh/sftp-server and not Subsystem sftp internal-sftp if you want to chroot and jail both SFTP and SHH logins.

It turns out that OpenSSH gets us most of the way there with the ChrootDirectory directive.

And so here are the steps required to create a minimal chroot jail on Ubuntu 12.04 LTS.

Let's get Jailed!

Step 1: Create your chroot directories

I've seen a few strategies for this including placing the chroot directory under /var/chroot.

In this case all of the clients on this server have a public_html subdirectory structure under their home directories. To make it easy to see who's been jailed we'll put our chroot jail in /home.

Thanks to Allan Field for the headstart here...

#Create our directories
sudo mkdir -p /home/jail/{dev,etc,lib,lib64,usr,bin,home}
sudo mkdir -p /home/jail/usr/bin
 
#Set owner
sudo chown root:root /home/jail
 
#Needed for the OpenSSH ChrootDirectory directive to work
sudo chmod go-w /home/jail

Step 1: Choose your commands

We'll offer a limited set of userspace applications. For these to work you need to copy the binary into its corresponding directory in the jail, as well as copy over any linked dependencies.

Allan Field pointed me to a handy script that can be used for bringing binary dependencies over for a given executable (as opposed to manually - via ldd and copying the results.)

The script can be found here... http://www.cyberciti.biz/files/lighttpd/l2chroot.txt.

We're going to offer bash, cp, ls, clear, and mkdir to our jailed users (for starters).

#First the binaries
cd /home/jail/bin
sudo cp /bin/bash .
sudo cp /bin/ls .
sudo cp /bin/cp .
sudo cp /bin/mv .
sudo cp /bin/mkdir .
 
#Now our l2chroot script to bring over dependencies
sudo l2chroot.sh /bin/bash
sudo l2chroot.sh /bin/ls
sudo l2chroot.sh /bin/cp
sudo l2chroot.sh /bin/mv
sudo l2chroot.sh /bin/mkdir

(This should really be wrapped up into a single bash script that takes both the binary and its dependencies).

The clear command requires terminal definitions...

# clear command
cd /home/jail/usr/bin
sudo cp /usr/bin/clear .
sudo l2chroot.sh /usr/bin/clear
#Add terminal info files - so that clear, and other terminal aware commands will work.
cd /home/jail/lib
sudo cp -r /lib/terminfo .

Step 2: Create your user and jail group

Create the jail group sudo groupadd jail

You can either create a new user using sudo adduser --home /home/jail/home/username username, or copy (and then later remove) the home directory of an existing user into the home/jail/home directory.

If you create a new user using sudo adduser --home /home/jail/home/username username - the home directory will be created in the jail, but the user's home directory in /etc/passwd will need to be edited to return it to /home/username - since the jail root will put home at the root again once the user is logged in.

Now add the user to the jail group sudo addgroup username jail

Step 3: Update sshd_config

We're going to edit the sshd_config file, removing the ForceCommand internal-sftp directive - since we don't want to limit our users to SFTP (you could maintain a second group and configuration for this).

Match Group jail
    ChrootDirectory /home/jail
    X11Forwarding no
    AllowTcpForwarding no
    AuthorizedKeysFile /home/jail/home/%u/.ssh/authorized_keys 

We've chrooted to /home/jail - and both SFTP and SSH logins will default to the user's home directory below the jail.

Restart the sshd daemon, and you're ready to go sudo /etc/init.d/ssh restart or service ssh restart

Try logging in via SSH or SFTP, and your jailed user will be dropped into their home directory under /home/jail/home, with a limited set of userspace applications, and no access to the parent environment.

Step 4: Bonus marks - give the user MySQL access

I'd like users to be able to upload and configure a site, including be able to perform mysql dumps and restores. Here's how to give them a MySQL prompt.

#Binaries for MySQL Client
sudo mkdir /home/jail/usr/local/mysql/bin
cd /home/jail/usr/local/mysql/bin
sudo cp /usr/local/mysql/bin/mysql .
sudo l2chroot.sh /usr/local/mysql/bin/mysql
cd /home/jail/lib/x86_64-linux-gnu
sudo cp /lib/x86_64-linux-gnu/libgcc_s.so.1 .

Note the 'undiscovered' dependancy on libgcc_s.so.1.

Wrapping Up!

This is a nice and simple solution that works thanks to OpenSSH's built in ChrootDirectory directive. It doesn't require any modification to the passwd file, and could fairly easily be wrapped up into a consolidated shell scrip for creating, updating and adding applications to the jail.

And that's it! And remember - Linux is fun ;-)

Category: 

Comments

I've done what you say, but, when I log in via ssh it says /bin/bash not found and closes the conection. What coul'd be wrong?? Thanks in advance...

Hi Omar - are you sure the user is a member of the jail group? I confess I stopped using this method for chroot a little while ago, as I simply didn't need this for the applications I was supporting.

Thanks for this tutorial! Works perfectly for me on Ubuntu 14.04. But when your users should authenticate with ssh-publickeys you have to add one line at the end of 'Match Group jail': AuthorizedKeysFile /home/jail/home/%u/.ssh/authorized_keys Otherwise openSSH will not find the users public key and authentication will fail. Maybe you can add this to your article.

Thanks jzdm! I'll update the article.

This is working grat for ssh, but when I try to use sftp, I get Connection closed. In the auth.log, I see the following: subsystem request for sftp by user testuser session closed for user testuser Any ideas? thanks

Hello there. Thanks for this how-to. However, something remains unclear for me : You create a new user or you use an existing user. For the latter : "or copy (and then later remove) the home directory of an existing user into the home/jail/home directory" I can't figure how this system will allow user in jail group to browse his actual homedir /home/user. Maybe it has to do with "since the jail root will put home at the root again once the user is logged in.", but I don't understand this either. I successfully set the environment with an existing user but when I delete the /home/jail/home/user dir, user can still log through ssh but his home dir is empty, of course, I would say. Is there something I missed ?

Hi, thanks for this wonderful tutorial. In this I need to allow the jail user to connect other SSH, for that I have added ssh command for them. When try to connect ssh from that user account I am receiving "No user exists for uid 1001". Any idea on this?

Hello Anthony, This is a great guide. I followed it step by step with an absolute posotive result. My jailed user can connect via putty and is able to see only it's own dir. However If I try to connect with winscp I get the following error log: 2016-05-23 16:18:50.768 Using SFTP protocol. . 2016-05-23 16:18:50.768 Doing startup conversation with host. > 2016-05-23 16:18:50.823 Type: SSH_FXP_INIT, Size: 5, Number: -1 . 2016-05-23 16:18:50.823 Server sent command exit status 127 . 2016-05-23 16:18:50.823 Disconnected: All channels closed * 2016-05-23 16:18:50.889 (EFatal) **Connection has been unexpectedly closed.** Server sent command exit status 127. * 2016-05-23 16:18:50.889 Cannot initialize SFTP protocol. Is the host running a SFTP server? A non-jailed user still able to connect and perform file transmission. Any idea?

Hi Peter - really sorry, but I stopped working on this a while back, having switched to a default set of restrictive permissions for most of my users that only require SFTP access.