Skip to main content


Dive deeper into the chroot command and learn how to isolate specific services and specific users.

Taking a deeper dive into chroot jails

In part one, How to setup Linux chroot jails,?I covered?the chroot command and you learned to use the chroot wrapper in sshd to isolate the sftpusers group. When you?edit sshd_config to invoke the chroot wrapper and give it matching characteristics, sshd?executes certain commands within the chroot jail or wrapper. You?saw how this technique could potentially be useful to implement?contained, rather than secure,?access for remote users.

Expanded example

I'll start by expanding?on what I?did before, partly as a review. Start by setting?up a custom directory for remote users. I'll?use the sftpusers group again.

Start by creating?the custom directory that you want to use, and setting the ownership:

# mkdir -p /sftpusers/chroot
# chown root:root /sftpusers/chroot

This time,?make root the owner, rather than the sftpusers group. This way,?when you?add users, they don't start out with permission to see the whole directory.

Next, create the user you?want to restrict (you?need to do this for each user in this case), add?the new user to the sftpusers group,?and deny?a login shell because these are?sftp users:

# useradd sanjay -g sftpusers -s /sbin/nologin
# passwd sanjay

Then, create the directory for sanjay and set the ownership and permissions:

# mkdir /sftpusers/chroot/sanjay
# chown sanjay:sftpusers /sftpusers/chroot/sanjay
# chmod 700 /sftpusers/chroot/sanjay

Next, edit the sshd_config file.?First, comment out the existing subsystem invocation and add the internal one:

#Subsystem sftp /usr/libexec/openssh/sftp-server
Subsystem sftp internal-sftp

Then add our match case entry:

Match Group sftpusers
ChrootDirectory /sftpusers/chroot/
ForceCommand internal-sftp
X11Forwarding no
AllowTCPForwarding no

Note that you're back to specifying a directory,?but this time, you?have already set the ownership to prevent sanjay from seeing anyone else's stuff. That trailing / is also important.

Then, restart sshd and test:

[skipworthy@milo ~]$ sftp sanjay@showme
sanjay@showme's password:
Connected to sanjay@showme.
sftp> ls
sftp> pwd
Remote working directory: /
sftp> cd ..
sftp> ls
sftp> touch test
Invalid command.

So. Sanjay can only see his own folder and needs to cd into it to do anything useful.

Isolating a service or specific user

Now, what if you?want to provide a usable shell environment for a remote user, or create a chroot jail environment for a specific service? To do this, create the jailed directory?and the root filesystem, and then create links to the tools and libraries that you need.?Doing all of this is a bit involved, but Red Hat provides?a script and basic instructions that make the process?easier.

Note:?I've tested the following in Red Hat Enterprise Linux 7 and 8, though my understanding is that this capability was available in Red Hat Enterprise Linux 6. I have no reason to think that this script would not work in Fedora, CentOS or any other Red Hat distro, but your mileage (as always)?may vary.

First, make your chroot directory:

# mkdir /chroot

Then run the script from yum that installs the necessary bits:

# yum --releasever=/ --installroot=/chroot install iputils vim python

The --releasever=/ flag passes the current local release info to initialize a repo in the new --installroot, defines where the new install location is.?In theory, you could make a chroot jail that was based on any version of the yum or dnf repos (the script?will, however, still start with the current system repos).?

With this tool, you?install?basic networking utilities like the VIM editor and Python. You?could add?other things initially if you?want?to, including whatever service you want?to run inside this jail. This is also one of the cool things about yum and dependencies. As part of the dependency resolution, yum makes the necessary additions to the filesystem tree along with the libraries. It does, however, leave out a couple of things that you need to add next. I'll?will get to that in a moment.

By now, the packages and the dependencies have been installed, and a new GPG?key was created for this new repository in relation to this new root filesystem.?Next, mount your ephemeral filesystems:

# mount -t proc proc /chroot/proc/
# mount -t sysfs sys /chroot/sys/

And set up your dev bindings:

# mount -o bind /dev/pts /chroot/dev/pts
# mount -o bind /dev/pts /chroot/dev/pts

Note that these mounts will not?survive a reboot this way, but this setup will let you?test and play with a chroot jail environment.

Now, test to check that everything is working as you?expect:

# chroot /chroot
bash-4.2# ls
bin dev home lib64 mnt proc run srv tmp var boot etc lib media opt root sbin sys usr

You can see that the filesystem and libraries were successfully added:

bash-4.2# pwd
bash-4.2# cd ..

From here,?you see the correct root and can't navigate up:

bash-4.2# exit

Now you've exited the chroot wrapper, which is?expected because you?entered it from a local login shell as root. Normally, a remote user should not be able to do this, as you?saw in the sftp example:

[skipworthy@milo ~]$ ssh root@showme
root@showme's password:
[root@showme1 ~]# chroot /chroot

Note that these directories were all created by root, so that's who owns them. Now, add this chroot to the sshd_config, because this time you will match just this user:

Match User leo
ChrootDirectory /chroot

Then, restart sshd.

You also need to copy the /etc/passwd and /etc/group?files from the host system to the /chroot directory:

[root@showme1 ~]# cp -vf /etc/{passwd,group} /chroot/etc/

Note: If you?skip the?step above, you?can log in, but the result will be unreliable and you'll be prone to errors related to conflicting logins

Now for the?test:

[skipworthy@milo ~]$ ssh leo@showme
leo@showme's password:
Last login: Thu Jan 30 19:35:36 2020 from
-bash-4.2$ ls
-bash-4.2$ pwd

It looks good. Now, can you?find something useful to do??Let's have some fun:

[root@showme1 ~]# yum --releasever=/ --installroot=/chroot install httpd

You?could?drop the releasever=/, but?I like to leave that in because it leaves fewer chances for unexpected results.

[root@showme1 ~]# chroot /chroot
bash-4.2# ls /etc/httpd
conf conf.d conf.modules.d logs modules run
bash-4.2# python
Python 2.7.5 (default, Aug 7 2019, 00:51:29)

So, httpd is there if you?want it, but just to demonstrate?you can?use a quick one-liner from Python, which you?also installed:

bash-4.2# python -m SimpleHTTPServer 8000
Serving HTTP on port 8000 ...

And now you have a simple webserver running in a chroot jail. In theory, you can?run any number of services from inside the chroot jail and keep them 'contained'?and away from other services, allowing you to expose only a part of a larger resource environment without compromising your user’s experience.

New to Linux containers? Download the Containers Primer and learn the basics.

Topics:   Linux   Containers  
Author’s photo

Glen Newell

Glen Newell is a Red Hat Certified Engineer with many years of experience in IT Systems Administration and Support. He spent many years wandering in the desert of closed OSs but is now happy to exclusively focus on open source solutions. More about me

Free Event: Red Hat Summit 2020 Virtual Experience

Attend the Red Hat Summit 2020 virtual experience, April 28-29.

Related Content