SFTP Chroot Jail

Howto create a sftp chroot jail

SFTP Chroot Jails are a simple and easy way of creating a secure area on your Linux system that can be used for transferring files. A SFTP chroot jail allows you to create a secure directory that confines a user to specific area.

In the following example we will create a SFTP chroot jail that will confine a user to a particular directory. Our remote server is running RHEL 6.6 (Red Hat Enterprise Linux). We will be connecting to our sftp server from an Ubuntu 15.04 system. The following sections will take you through the simple set up that is required.

SFTP Chroot Jail

First we are going to modify the file "/etc/ssh/sshd_config". Comment out the line that begins Subsystem and replace it with the following line:

Subsystem       sftp    internal-sftp

Next add the following lines to the bottom of the same file:

Match Group sftpgroup
      ChrootDirectory %h
      ForceCommand internal-sftp
      AllowTcpForwarding no
      X11Forwarding no

The file "/etc/ssh/sshd_config" is the OpenSSH Daemon configuration file. Below is an explanation of the parameters used above:

Subsystem The subsystem option allows for the configuration of an external subsystem. The basic syntax is for a subsystem name, followed by a command.
On our system we are specifying “internal-sftp” which allows us to implement an in process "sftp” server. This is used to simplify the configuration of a ChrootDirectory.

Match is known as a conditional block. If all of the criteria of the Match line are met, then the following lines are used instead of the settings found in the global section.

In our example we are specifying a "Group" called sftpgroup. You may change this name to something that matches your system naming convention. This line means that the following lines will only be applicable to members of the specified group.

ChrootDirectory %h specifies that the user will be chrooted to their home directory.

The line "ForceCommand internal-sftp" will force execution of the internal-sftp subsystem.

The line "AllowTcpForwarding no" Specifies whether TCP forwarding is permitted. The default setting is “yes”. Note that disabling TCP forwarding does not improve security unless users are also denied shell access.

X11Forwarding no specifies that X11 forwarding is not allowed.

Creating a sftp user and group

The next part of this tutorial will show you how to create the user and group that we are going to use in our example. Here we will be using standard commands for the creation of the user and associated group.

Create a sftp group

To create a group we use the command groupadd. Note the group you create must be the group that you have specified in the "sshd_config" file. In our example we will create a group called "sftpgroup".

groupadd sftpgroup

Create the sftp user account

To create a user, we will use the "useradd command. Here we will specify that the user must be a member of the group sftpgroup and that their default shell is set to nologin. By specifying the nologin option, we can limit the users access to only a sftp connection.

useradd -G sftpgroup -s /sbin/nologin sftpuser

Change the ownership and permissions of the sftpuser

When using a chroot jail, it is important to set the specified top level directory to be owned by root. To change the ownership from the normal user to that of the root user, we use the command chown.

chown root:root /home/sftpuser

Next we change the permissions on the directory as follows:

chmod 755 /home/sftpuser/

Create directory structure for sftpuser

In the next step we will create an upload and download directory structure. We will then grant the necessary privileges to the sftpuser.

cd /home/sftpuser/

mkdir upload

mkdir download

chown sftpuser:sftpgroup upload

chown sftpuser:sftpgroup download

You should now have a similar directory structure with the following ownership and permissions set.

# ls -ld /home/sftpuser/
drwxr-xr-x. 6 root root 4096 Jun  7 09:37 /home/sftpuser/

# ls -ld /home/sftpuser/upload/
drwxr-xr-x. 2 sftpuser sftpgroup 4096 Jun  7 09:37 /home/sftpuser/upload/

# ls -ld /home/sftpuser/download/
drwxr-xr-x. 2 sftpuser sftpgroup 4096 Jun  7 09:37 /home/sftpuser/download/

Create a Password for the sftpuser

For the user to access the server, a password will need to be assigned to the account that was created earlier. To do this, we will use the command "passwd"

passwd sftpuser

Configure iptables firewall rules

If you are using a firewall, you may need to open the port that your ssh daemon is running on. In this example we are using port 22. This is the default port for ssh and sftp. If you need to open a port using iptables, you may configure the firewall as follows:

First verify that you are using iptables and that it is active by issuing the following command: service iptables status

[root@rhel01a ~]# service iptables status
Table: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    ACCEPT     all  --             state RELATED,ESTABLISHED 
2    ACCEPT     icmp --             
3    ACCEPT     all  --             
4    ACCEPT     tcp  --             state NEW tcp dpt:22 
5    REJECT     all  --             reject-with icmp-host-prohibited 

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         
1    REJECT     all  --             reject-with icmp-host-prohibited 

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

From the above output we can see that port 22 is already open:

4    ACCEPT     tcp  --             state NEW tcp dpt:22 

If you can not see port 22 open, you will need to issue the following command: iptables -A INPUT -p tcp --dport 22 -j ACCEPT

[root@rhel01 root]# iptables -A INPUT -p tcp --dport 22 -j ACCEPT

For more information on using iptables, see our quick user guide iptables

Configure SELinux Settings for Chroot Jails

If you are running SELinux you will need to grant read/write access to chroot home directories.

To check if you are using SELinux in enforcing mode, you can issue the following command: sestatus

[root@rhel01a ~]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          enforcing
Policy version:                 24
Policy from config file:        targeted

If you are running in enforcing mode, then you will need to grant the read/write permissions by running the following command: setsebool -P ssh_chroot_rw_homedirs on

setsebool -P ssh_chroot_rw_homedirs on

For information regarding SELinux, see our Introduction to SELinux

Testing access to the SFTP Server

The final test now is to connect to our test server.

john@ubuntu01-pc:~$ sftp sftpuser@
sftpuser@'s password: 
Connected to

sftp> pwd
Remote working directory: /
sftp> ls
download  upload    
sftp> cd upload/

sftp> lcd /home/john

sftp> put test.txt
Uploading test.txt to /upload/test.txt
test.txt                                      100%   15     0.0KB/s   00:00    
sftp> ls -l
-rw-r--r--    1 502      503            15 Jun  7 13:24 test.txt

sftp> cd ..
sftp> pwd
Remote working directory: /
sftp> cd download/
sftp> pwd
Remote working directory: /download

sftp> cd /
sftp> pwd
Remote working directory: /
sftp> quit

In the above example we initiated our sftp connection by issuing the command sftp sftpuser@

(sftpuser is the user we are using to connect with and the address is the address of our remote server).
You can replace this address with your address or the hostname of the server you are connecting to.

First we issue the command pwd as this will display our current working directory.

If we issue the ls command we can see the two directories that we created earlier.

Next I changed the remote directory to the upload directory using the command cd upload

As a test I then changed the local directory on the local client to /home/john where I have a small test file called test.txt. The command lcd is used to specify a local directory to be used.

As I test I used the put command to upload a file to the remote directory. The output can be seen in the above example.