/ centos

SFTP Chroot Jail in CentOS Linux


Secure FTP uses openssh and was engineered by the IETF between 2001 and 2007. It has the potential to replace the insecure and older File Transfer Protocol (FTP). Another alternative to FTP and SFTP is WebDAV, which uses HTTP/TCP pipelining technology and hence does considerably speed up file transfers. However if you wanted WebDAV to be secure you would have to go through the hassles of creating a working SSL connection. This article will focus on implementing a SFTP Chroot Jail for SFTP usage. It has been last updated in October 2013 at the time of writing, to incorporate some of the suggestions by the readers in the comments.

SFTP should work out of the box if SSH is already running on your server. Just connect from your client machine with

sftp user@hostname.tld

The SFTP connection itself is getting tunneled over SSH. However the user you are using to log in will have access to your entire root file system as well as being able to login via SSH and administer a whole different kind of damage if he wanted to. So what we want to achieve is to not only prohibit the user from using SSH to login, we also want to restrict him or her from having access to certain areas of our file system. We will jail him to his home directory or to a particular Web site directory. In order to jail the user, we will have to chroot him, which means as much as changing his root.

Installation of OpenSSH 5.6

To achieve a simple chroot jail, software-wise you need openSSH 5 or greater.

At the time of this blog post (Nov 2010), CentOS 5.5 still shipped with the one-year old openSSH 4.6. In order to get openSSH 5 on oour system, we best compile a RPM package from the latest openSSH 5.6 sources and install it on CentOS. This is how you can achieve that:

#Subsystem      sftp    /usr/lib64/misc/sftp-server
Subsystem       sftp    internal-sftp
AllowGroups fullssh sftponly

Match Group sftponly 
    ChrootDirectory /var/www/html/petes-website
    ForceCommand internal-sftp 
    X11Forwarding no 
    AllowTcpForwarding no

Command line Fu explained

First the yum package manager installs the GNU compiler together with important tools like make. Then yum installs the openssl development packages and rpm-build.

Then you should choose a repository location, we chose the RWTH Aachen. You also fetch the GPG signature and import it to your local gpg databse in order to verify the package. The rest comes down to building the rpm package, without GUI support like X11 or GNOME, since a graphical user interface isn't usually needed on a server.

I found

perl -i.bak -pe 's/^(%define no_(gnome|x11)_askpass)\s+0$/$1 1/' openssh.spec 

to be very elegant and I liked also

cd /usr/src/redhat/RPMS/uname -i

(use backticks around uname -i). The latter changes directory to the correct build version of your kernel. I must credit some of these steps to BinBlog.

Verify Installation

We better check if it worked:

rpm -qa | grep ssh

.. which should print out:




These have been the pre-requisites for installing a chroot jail with SFTP. In the following section we will have a loot at how to configure SFTP users and prepare your directory structure.

Structure of SFTP Chroot

Creating Groups

First, we setup two new groups on your Linux system. fullssh and sftponly. The group fullssh is going to have full access to the Linux filesystem, as its name gives away. Just add your main user to the fullssh supplementary group. The other group called sftponly is designed for the SFTP user, let's call him pete. Pete is going to be jailed to a particular directory and will also be restricted from using SSH.

groupadd sftponly

useradd pete

usermod -aG sftponly pete

In above snippet you could also omit the -a switch, which I put there to ensure our user is appended to a supplementary/secondary group instead of having the user or the group get created from scratch. You can verify that permissions are setup accordingly by issuing a groups pete.

Configure sshd_config

Now edit the file /etc/ssh/sshd_config. Comment out the default entry for the SFTP service and set up the chroot directory of choice. In this example I used /var/www/html, the root of Web sites on most servers.

#Subsystem      sftp    /usr/lib64/misc/sftp-server
Subsystem       sftp    internal-sftp
AllowGroups fullssh sftponly

Match Group sftponly 
    ChrootDirectory /var/www/html/petes-website
    ForceCommand internal-sftp 
    X11Forwarding no 
    AllowTcpForwarding no

In this context it would be great to re-read your ssh config file without restarting the whole server or you will be kicked out of the running session. A typical ´HUPKILLwon't do the trick. You have to find out the Process ID (PID) of your **root sshd dameon process** withps aux | grep sshdand then re-read sshd_config accordingly withkill -HUP 1234`, where 1234 is the PID of the root process.

Directory Structure and Permissions

We now proceed to setup the directories and the permissions of the directory structure. This has to be done with great care.

mkdir -p /var/www/html/petes-website

chmod 755 /var/www/html/petes-website

chown root:sftponly /var/www/html/petes-website

chown -R pete:sftponly /var/www/html/petes-website

First, you create the directory petes-website with the -p switch. The switch will take care of creating all necessary parent folders, just in case you don't have a /var/www/html directory already.

Then you set the directory permission bits to 755. Why not set permissions of the chroot directory to the safer 750 bits? While this might provide better security in most Web server scenarios, this locked my Web server out from accessing the directory and when I tried to access my Web site through a Browser it produced a HTTP 403 Forbidden status code.

With the first of the two chown lines above you change the owners of the directory /var/www/html/petes-website to root user-wise and to sftponly group-wise. We made the user pete a member of the sftponly group earlier. The second chown line gives ownership recursively to all files in the directory petes-website to the user pete.

Verify Setup

The permissions have to be setup in the following manner to make the SFTP login chain work:

$ls -lishad /var/www/html/petes-website

drwxr-xr-x 3 root sftponly 4.0K Nov 9 /var/www/html

$ls -lisha /var/www/html/petes-website

drwxr-xr-x 8 pete sftponly 12.4K Nov 9 /var/www/html/petes-website/index.html

drwxr-xr-x 8 pete sftponly 25.0K Nov 9 /var/www/html/petes-website/about-pete.html

drwxr-xr-x 8 pete sftponly 15.1K Nov 9 /var/www/html/petes-website/contact.html

Now if you login via SFTP with the user pete, SSH will handle the login process until the user pete is authenticated. The user is then jail rooted to the petes-website directory from above example.

When the user pete tries to login to your server via SSH the ForceCommand internal-sftp directive inside sshd_config will restrict pete from login via SSH and you should see:

ssh pete@petes-website.org

This service allows sftp connections only.

Connection to petes-website.org closed.

Full Chroot

Consequently, ommiting the ForceCommand internal-sftp directive in the sshd_config file will allow members of the sftponly group to access your system via SSH. You will have to setup at least a rudimentary chroot environment by providing necessary programs and libraries like bash, to name the most important one. This is described at HowtoForge.

By using the internal-sftp directive we made sure that we don't need a fully chroot environment with scripted access to tools or symlinks - therefore it should be rather difficult for an attacker to escape the jail. However you should be aware that there exists a chroot exploit since 1999. That is why the Solaris and Linux community stopped to consider a chroot jail being completely secure approach. However it is possible to harden a shell chroot environment.

I hope you enjoyed this article. I would appreciate your thoughts on the topic of server security in the comments or a blacklink from your blog or forum.

SFTP Chroot Jail in CentOS Linux
Share this