scp in a chroot jail

This guide is for allowing a user to login via SSH and/or use scp to copy files to a system. I’m on CentOS 7 and most of the documentation I found does not address this particular situation. They either use jailkit, which is not available in the stock repository for CentOS 7, or incorrectly declare that SSH’s internal-sftp allows scp, even rsync.

This is a manual recipe for making a chroot jail that allows scp and ssh login that requires nothing beyond the base install of a CentOS 7. This is derived from a good article by ​Allan Feid.

Add a user that will be allowed to ssh/scp into the system. In our example we’ll use “vagabond”. Be sure to set a sensible password:

sudo useradd vagabond
sudo passwd vagabond

With useradd there will be a home directory for vagabond, but the permissions are setup wrong for this use case. Ownership needs to be root and permissions 755:

sudo chown root.root /home/vagabond
sudo chmod 755 /home/vagabond

Setup all the directories needed. This needs to emulate the / directory to a bare minimum. We need a dev, etc, lib, usr, and bin directory as well as /usr/bin/.
sudo mkdir -p /home/vagabond/{dev,etc,lib,lib64,usr,bin,home/vagabond}
sudo mkdir -p /home/vagabond/usr/bin

With above we also created a home directory for vagabond which we need to allow vagabond to actually write to:

sudo chown vagabond.vagabond /home/vagabond/home/vagabond

You also need the /dev/null file:

sudo mknod -m 666 /home/vagabond/dev/null c 1 3

Fill up the etc directory with a few minimum files:

​sudo cp /etc/ /etc/ /etc/nsswitch.conf /etc/hosts /home/vagabond/etc

Once this is done you need to figure out what commands you want accessible by the limited users. In this case I only want the users to be able to get into bash, use ssh, scp, ls, cp, rm, mkdir and rmdir. So you must copy the needed binaries to the jail.

sudo cp /usr/bin/bash /usr/bin/ls /usr/bin/ssh /usr/bin/scp /usr/bin/cp /usr/bin/rm /usr/bin/mkdir /usr/bin/rmdir /home/vagabond/usr/bin

Now that you’ve got all the binaries in place, you need to add the proper shared libraries. To find out what libraries are needed you can run ldd /path/to/bin. The output looks similar to this:

[user@host ~]$ ldd /usr/bin/ls => (0x00007fff349f3000) => /lib64/ (0x00007f21de29d000) => /lib64/ (0x00007f21de098000) => /lib64/ (0x00007f21dde8e000) => /lib64/ (0x00007f21ddacd000) => /lib64/ (0x00007f21dd86c000) => /lib64/ (0x00007f21dd646000) => /lib64/ (0x00007f21dd442000)
/lib64/ (0x00007f21de4c8000) => /lib64/ (0x00007f21dd23d000) => /lib64/ (0x00007f21dd020000)

You have to manually copy each file to the lib or lib64 directory in your jail. Doing things manually is pretty error prone, but given that I don’t want to download anything or run scripts, I use this long shell one-liner:

ldd /usr/bin/bash /usr/bin/ls /usr/bin/ssh /usr/bin/scp /usr/bin/cp /usr/bin/rm /usr/bin/mkdir /usr/bin/rmdir | awk ‘{ print $3 }’ | egrep -v ^’\(‘ | sort | uniq | xargs -I files sudo cp files /home/vagabond/lib64/

Be sure to adjust the list of files you want to run ldd on to match the files you decided to copy and to adjust the path of the lib or lib64 directory where you are copying them.

Then manually copy ld-linux library, which is not referenced by ldd:

sudo cp /lib64/ld-linux* /home/vagabond/lib64/

Now we edit SSH “/etc/ssh/sshd_config” file to allow the user to login and to automatically jail them:

Subsystem sftp internal-sftp
Match Group sftp
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no

service sshd restart

​su vi /etc/ssh/sshd_config

Add the following at the end:

Match User vagabond
X11Forwarding no
AllowTcpForwarding no
ChrootDirectory %h
PasswordAuthentication yes

The key line here is ChrootDirectory; this is what will place the user in the chroot jail.

On top of that I allow PasswordAuthentication for this special user because I typically do all my SSH authentication with PubkeyAuthentication and ban PasswordAuthentication.

Save the file and restart the SSH server:

sudo service sshd restart