Local Security
By the end of this section, you should know:
- The purpose of a
chrootenvironment and how it enhances local security by restricting users to a defined directory. - How to create a basic
chrootdirectory and structure it to mimic a limited root file system. - How to set up and test the
chrootenvironment to ensure users are confined to their pseudo-root directory. - The process for identifying and copying necessary binaries and their dependencies into a
chroot. - Basic troubleshooting techniques for common issues that may arise when setting up or entering a
chroot. - The limitations of
chrootfor security and how it serves as a foundational concept for containerization technologies like Docker. - How to configure SSH to restrict specific user groups to a
chrootenvironment for added security.
Getting Started
Security challenges predominantly emanate from network interactions;
however, we also need to safeguard a system from potential internal threats.
This can be achieved by enforcing file permissions and ensuring that users lack certain types of access,
such as sudo privileges.
Take, for instance, the program /usr/bin/gcc.
gcc serves as the GNU C and C++ compiler.
This means it translates C or C++ source code into executable programs (like exe programs on Windows computers).
Unrestricted access to this compiler could potentially allow users
to create programs capable of compromising the system
(I know, based on personal experience).
In the following section, we will shift focus to external threats and learn about setting up a firewall.
In this section, we focus on internal threats and learn how to create a chroot environment.
This is a specialized environment that restricts user operations or processes to a defined directory,
thereby bolstering system security.
By understanding how to set up a chroot environment,
we will learn an effective strategy that mitigates risks stemming from within the system.
(A chroot environment can also be used to mitigate external threats.)
chroot
As we all know, the Linux file system has a root directory /, and
under this directory are other directories like /home, /bin, and so forth.
A chroot (change root) environment is a way to create a fake root directory
at some specific location in the directory tree, and
then build an environment in that pseudo root directory that offers some applications.
Once that environment is setup, we can confine a user account(s) to that pseudo directory, and
when they login to the server,
they will only be able to see (e.g., with the cd command) what's in that pseudo root directory and
only be able to use the applications that we've made available in that chroot.
Thus, a chroot is a technology used to change the "apparent root / directory for a user or a process" and
confine that user to that location on the system.
A user or process that is confined to the chroot cannot easily see or access the rest of the file system and
will have limited access to the binaries (executables/apps/utilities) on the system.
From its man page:
chroot (8) - run command or interactive shell with special root directory
Although it is not security proof, it does have some useful security use cases.
To mitigate external threats, some use chroot to contain DNS or web servers, for example.
chroot is also the conceptual basis for some kinds of virtualization technologies that are common today,
like Docker.
And Unix-like operating systems, like FreeBSD, employ more advanced but comparable technologies like Jails.
Creating a chroot
In this tutorial, we are going to create a chroot.
-
First, we create a new directory for our chroot. That directory will be located at
/mustafar(but it could be elsewhere). Note that the normal root directory is/, but for the chroot, the root directory will be/mustafareven though it will appear as/in thechroot.Depending on where we create the chroot, we want to check the permissions of the new directory and make sure it's owned by root. If not, use
chown root:root /mustafarto set it.Create directory:
sudo mkdir /mustafarCheck user and group ownership:
ls -ld /mustafar -
We want to make the
bashshell available in the chroot. To do that, we create a/bindirectory in/mustafar, and copybashto that directory.which bash sudo mkdir /mustafar/bin sudo cp /usr/bin/bash /mustafar/bin/ALTERNATIVELY: use command substitution to copy
bash:sudo mkdir /mustafar/bin sudo cp $(which bash) /mustafar/bin -
Large software applications have dependencies, aka libraries. We need to copy those libraries to our chroot directory so applications, like
bash, can run.To identify libraries needed by
bash, we use thelddcommand:ldd /usr/bin/bashDo not copy and paste!! Output (output may vary depending on your system):
linux-vdso.so.1 (0x00007fff2ab95000) libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007fbec99f6000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbec97ce000) /lib64/ld-linux-x86-64.so.2 (0x00007fbec9ba4000)Ignore the first item in the output (
linux-vdso.so.1). But we will need the libraries in the last three lines. -
Next we create directories for these libraries in
/mustafarthat match or mirror the directories they reside in. For example, in the abovelddoutput, two directory paths are highlighted:/lib/x86_64-linux-gnuand/lib64. Therefore, we need to create directories with those names in/mustafar.To do that, use the
mkdircommand to create a/mustafar/lib/x86_64-linux-gnu/directory and a/mustafar/lib64for the libraries. We need to name the library directories after the originals to stay consistent with the main environment.sudo mkdir -p /mustafar/lib/x86_64-linux-gnuAnd then:
sudo mkdir /mustafar/lib64Then we proceed to copy (not move!) the libraries to their respective directories in the /mustafar directory:
cd /mustafar/lib/x86_64-linux-gnu/ sudo cp /lib/x86_64-linux-gnu/libtinfo.so.6 . sudo cp /lib/x86_64-linux-gnu/libc.so.6 . cd /mustafar/lib64/ sudo cp /lib64/ld-linux-x86-64.so.2 . -
Finally, we can test the
chroot:sudo chroot /mustafarIf successful, you should see a new prompt like below:
bash-5.1#If you try running commands that are not part of Bash itself, you'll encounter some errors.
We do have access to some commands, like
help,dirs,pwd,cd, and more because these are builtin tobash. Utilities not builtin tobashare not yet available in our chroot. These includels,cat,cp, and more. The following is a brief example of interacting in a limited chroot environment with no outside utilities available:bash-5.1# ls bash: ls: command not found bash-5.1# help bash-5.1# dirs bash-5.1# pwd bash-5.1# cd bin/ bash-5.1# dirs bash-5.1# cd ../lib64/ bash-5.1# dirs bash-5.1# cd .. bash-5.1# for i in {1..4} ; do echo "$i" ; doneTo exit the
chrootenvironment, simply typeexit:bash-5.1# exit
Exercise
Use the ldd command, to add additional binaries.
Make the following utilities/binaries available in the /mustafar chroot directory:
lssleep
Troubleshooting Common chroot Setup Errors
When setting up a chroot environment, you may encounter an error like:
chroot: failed to run command '/bin/bash': No such file or directory
This error often occurs if the chroot environment is missing critical files or directories,
such as the bash executable or its required libraries.
Here are some steps to resolve this:
-
Check for the Bash Binary: Ensure that the
bashexecutable has been correctly copied to/mustafar/bin/:sudo ls /mustafar/bin/bashIf this file isn't there, go back to the step where you copy
bashto thechrootdirectory. -
Verify Library Dependencies: The
bashbinary requires certain libraries to run. Use thelddcommand to list these dependencies and confirm they are copied to/mustafar:ldd /usr/bin/bashEnsure each library listed is copied to the matching directory within
/mustafar, such as/mustafar/lib/x86_64-linux-gnu/and/mustafar/lib64/. -
Correct File Structure: Confirm that your
chrootdirectory structure mirrors the actual root structure. The paths within/mustafarshould match the paths of the dependencies found usingldd.
After confirming these items, try running chroot again:
sudo chroot /mustafar
If these checks don't resolve the issue,
double-check permissions on the chroot directory to ensure root ownership:
sudo chown root:root /mustafar
Conclusion
Systems need to be secure from the inside and out. In order to secure from the inside, system users should be given access and permissions as needed.
In this section, we covered how to create a chroot environment.
The chroot confines users and processes to this pseudo root location.
It provides them limited access to the overall file system and to the software on the system.
We can use this chroot to confine users and processes, like apache2 or human users.
Any user listed in /etc/passwd can be chrooted, and most users listed in that file are services.
Restricting a human user to a chrooted environment may not be necessary.
On a multi-user system, proper education and training about the policies and
uses of the system may be all that's needed.
Alternatively, when creating user accounts, we could make their default shell rbash, or restricted bash.
rbash limits access to a lot of Bash's main functions, and for added security,
it can be used in conjunction with chroot.
See man rbash for more details.
In summary, if a stricter environment is needed, you know how to create a basic chroot environment.
Additional Sources:
- How to automatically chroot jail selected ssh user logins.
- BasicChroot
- How to Use chroot for Testing on Ubuntu
- How To Setup Linux Chroot Jails
Appendix A: Non-Google Cloud Systems
Our user accounts and connections to our Google Cloud virtual instances are managed on the Google Cloud console,
and we reach these instances using the gcloud compute ssh command or through the web interface.
The gcloud command is special software that we installed on our personal systems and
authentication happens via our Google accounts.
However, on traditional remote systems,
we use ssh with its standard syntax, which is: ssh user@domain.com or ssh user@<ip_address>,
where user is the account name managed directly on the server and domain.com is the host name of the server.
On those traditional types of systems,
we can take advantage of chroot to isolate user accounts to a chrooted environment.
There are a number of ways to do this, but
below I demonstrate how to isolate users to a chrooted environment based on their group membership.
-
Let's create a new user. After we create the new user, we will
chrootthat user going forward.sudo adduser vader -
Create a new group called
mustafar. We can add users to this group that we want to jail in a chrooted environment.sudo groupadd mustafar sudo usermod -a -G mustafar vader groups vader -
Edit
/etc/ssh/sshd_configto direct users in thechrootjailgroup to thechrootdirectory. Add the following line at the end of the file. Then restart ssh server.sudo nano /etc/ssh/sshd_configThen add:
Match group mustafar ChrootDirectory /mustafarExit
nano, and restartssh:systemctl restart sshd -
Test the
sshconnection for thevaderuser. Here I usesshon the local system to connect to the local system, simply to test it.ssh vader@localhost -bash-5.1$ ls -bash: ls: command not found exitThat works as expected. The user
vaderis now restricted to a special directory and has limited access to the system or to any utilities on that system.
Appendix B: Additional Tools for Securing Multi-User Shell Systems
In addition to chroot and rbash, other Linux tools can help secure multi-user, shell-accessible systems.
These tools can be used to restrict file modifications, monitor system changes, and limit user actions.
Together they provide an extra layer of control and protection.
-
chattr(Change File Attributes)The
chattrcommand changes file attributes on Linux filesystems. By setting certain attributes on files, you can restrict users—even with superuser permissions—from modifying critical files. This is particularly useful for preventing accidental or malicious deletion or alteration of configuration files and other sensitive data.- Common Usage: The most frequently used option is the
+i(immutable) attribute, which prevents modification or deletion.
sudo chattr +i /path/to/important/fileOnce this attribute is set, the file cannot be modified, renamed, or deleted until the attribute is removed with
chattr -i.- Other Options: There are additional flags to explore, such as
+a, which allows only appending to a file, which is useful for log files that should not be altered.
- Common Usage: The most frequently used option is the
-
lsattr(List File Attributes)The
lsattrcommand is used to view the attributes set bychattr. This command shows you which files are immutable or otherwise restricted. It allows administrators to verify that critical files have the appropriate protections.- Common Usage:
lsattr /path/to/important/fileThis command outputs a list of attributes and helps administrators quickly identify files that are protected or have special restrictions.
-
sudoandsudoersConfigurationThe
sudocommand grants specific users permission to execute commands as superuser, but thesudoersfile can also be configured to limit which commands a user may execute withsudo. By restrictingsudopermissions, you can allow users access to only the commands they need to perform their roles.- Common Usage: Open the
sudoersfile withvisudoto edit user permissions. For example, to allow a user only to uselsandcatwithsudo, add:
username ALL=(ALL) /bin/ls, /bin/cat - Common Usage: Open the
-
ulimit(User Limits)The
ulimitcommand sets resource limits for user sessions, such as maximum file sizes, number of open files, and CPU time. This is essential in preventing users from consuming excessive resources, which could slow down or crash the system.- Common Usage: To set a file size limit of 100MB for a session, use:
ulimit -f 100000You can make these limits permanent for specific users by adding them to the user's shell configuration file (e.g.,
~/.bashrc) or to the/etc/security/limits.conffile for global settings. If you add them to a user's~/.bashrcfile, you can use thechattrcommand to prevent the user from editing that file. -
faillockand Account Lockout Policiesfaillockhelps protect against brute-force attacks by locking user accounts after a specified number of failed login attempts. This can prevent unauthorized access to user accounts.- Common Usage: To set a policy that locks an account for 10 minutes after three failed login attempts,
edit
/etc/security/faillock.conf:
deny = 3 unlock_time = 600Then, restart your authentication services to apply the changes.
- Common Usage: To set a policy that locks an account for 10 minutes after three failed login attempts,
edit
-
iptablesfor Access ControlWhile traditionally used for network security,
iptablescan also be configured to control user access to certain resources or services. For example, you can restrict SSH access to specific IP addresses. This reduces the attack surface on multi-user systems.- Common Usage: To limit SSH access to users coming from a specific IP address:
sudo iptables -A INPUT -p tcp --dport 22 -s <allowed_ip> -j ACCEPT sudo iptables -A INPUT -p tcp --dport 22 -j DROPOn Debian-based systems, including Ubuntu, you can use the
ufwcommand (Uncomplicated Firewall) instead ofiptables:To permit SSH access (port 22) only from a specific IP address, use:
sudo ufw allow from <allowed_ip> to any port 22To block SSH access from all other IPs, use:
sudo ufw deny 22For example, to block SSH traffic from
192.168.1.100, you would write:sudo ufw allow from 192.168.1.100` to any port 22 sudo ufw deny 22Make sure
ufwis active and running with these commands:sudo ufw enable sudo ufw status
Combined with chroot and rbash,
these create a layered approach to security for multi-user shell systems.
Each tool has specific use cases, and
together they help administrators establish a secure and controlled environment.