A while ago, I bought a Raspberry Pi that I used as a Linux server with Raspbian to install Pihole in my house.
Editor’s note : Raspberry Pi are low-end small computers that can be used for a lot of different projects such as servers, robotic, retro-gaming or whatever your imagination can think of actually. Raspbian is a Debian version explicitly made and optimized for Raspberry Pi. Pihole is an ads blocker/proxy really easy to configure for your entire network.
A colleague also installed a Pihole in his house recently, so we were discussing about how we both configured it, exchanging some configuration tips, etc.. (Hi Oliver).
It made me want to reconfigure my Pihole and Raspbian installation, both in terms of functionality and security.
I’m happy with what I came up with and, as I’m really interested about security, I thought it will be a good idea to do a sort of “write-up” article about how I secured my Raspbian Linux server on my Raspberry Pi.
I’m gonna take my Raspbian/Pihole configuration as an example to illustrate this article, but keep in mind that those are basic configurations that can easily be applied and adapted on any Linux servers, depending on your needs.
Let’s begin, shall we ?
If you want to see how I configured my Pihole in term of functionality, click on this link
First thing first… passwords !
That will probably sounds obvious but take that as quick reminder 😉
I have 3 users accounts on my server :
– root (default Linux super-administrator)
– pi (default administrator Raspbian user, automatically created during the Raspbian installation)
– pihole (default Pihole user, automatically created during the Pihole installation)
All of those users have a strong and different password.
I personally consider a password as “strong” if it follows the next rules :
– At least 8 characters
– At least one uppercase and one lowercase
– At least one special character (@ – _ , ; % = # &)
– At least one number
You can change your password using the “passwd” command on your Linux server :
[pi@pihole ~]$ passwd → change password for the current user (“pi” in this case) [pi@pihole ~]$ sudo passwd pihole → change password for the user “pihole” (you’ll need sudo right to change an other user’s password)
So, this will be my first advice.
Enumerate your different users and make sure they all use a different and strong password.
Secure the root account :
The root account is obviously the most sensitive account of your server. It has full right on your system and can basically do anything. By the way…
You should never use it directly, even for administrator needs. Use sudo instead, that’s what it’s here for. Except for some special installations/configurations or deep debugging, leave the root account alone !
So what ? The root account is sensitive and I shouldn’t use it myself, do I need to deactivate it ?!
Well, yes… At least sort of.
You should denied the access to the root account over ssh by modifying the sshd_config file :
[pi@pihole ~]$ sudo vi /etc/ssh/sshd_config [...] PermitRootLogin no [...] [pi@pihole ~]$ sudo systemctl restart sshd → restart the sshd service to apply configuration
By doing this, you prevent anyone to log directly into the root account over ssh (even if they entered the right password). It is a solid solution to prevent brute-force attack for instance.
[rcandau@Elementary-Linux ~]$ ssh root@pihole root@pihole's password: Permission denied, please try again.
Don’t worry tho, you’ll still be able to log into the root account if needed. But you’ll need to connect to an other user first and use the “su” command just like you would do to connect to any other user.
[pi@pihole ~]$ su - Password : root@pihole:~#
This way, your root account will be protected against suspicious ssh login attempts as they are deactivated and you also make sure that anyone login as root does have a legit initial access to the server.
Okay, but what if my “normal” user is inaccessible for some reasons (‘cause I broke it) ? I’ll not be able to log to my root account to debug ?!
We’re just talking about ssh connection here. If the above scenario happens to me, I just need to connect a keyboard and a monitor to my server and I’ll be able to log into my root account directly without any problem.
If your server is a virtual one, you can just use the remote console included in your hypervisor solution to log into the root account directly.
I will not write an entire course about Linux permissions, I will just show you how I setup permissions for specific and sensitive files.
I created a bunch of scripts to automatically perform some specific actions on my Pihole instance on my server, such as updating it, compress/delete old log files, etc…
Those scripts are meant to be executed by the “pihole” user and no one else.
When you’re dealing with sensitive files such as scripts for instance (specially when they will be executed with sudo rights), make sure that you set your permissions correctly on it.
This is what I usually do (chmod 750) :
-rwxr-x--- 1 pi pihole 358 févr. 7 10:20 pihole_update.sh
So I put my “pi” user as the owner of the file, which is the user I’m using to administrate my server. That means that no one else than him can modify the permissions of this file (only the explicit owner of the file can modify permissions).
The “pihole” user only have read and execute permissions through the group permissions,but cannot modify the file (write permission). It is very important that this user cannot write into the script as it will be executed with sudo (more on that on next point).
Anyway, the statement here is to forget about unnecessary permissions and only set the useful/needed ones.
The “chmod 750” (full permissions for the owner, read and execute for the group and no permissions at all for the rest of the world) while putting your administrator account as the owner and the user that will execute the script as the group is a good solution to me.
One of the biggest security threat you can encounter on your server is misconfigured “sudo” permissions.
Sudo is a way to elevate your privileges to the super-administrator (root) ones temporarily to perform a specific action.
You need to make sure that users allowed to run “sudo” have actually a need of doing so and you may also need to filter the way they can use it and what they can or cannot do with it.
Is your user allowed to run sudo ?
There’s a user group created by the sudo binary which automatically give sudo permissions to any users belonging to this group. This group is often simply called “sudo” on most Linux systems but can be called differently on some particular distributions (for instance, it is called “wheel” on Red Hat based distributions).
To check the group membership of a user, you can use the “id” command :
[pi@pihole ~]$ id → Check on the current user uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),105(input),109(netdev),997(gpio),998(i2c),999(spi) [pi@pihole ~]$ id pihole → Check on the specified user (“pihole” in this case) uid=999(pihole) gid=995(pihole) groups=995(pihole),33(www-data)
So, as you can see, my “pi” user is a sudoers (this how we often call a member of the sudo group), but my « pihole » user is not a member of the sudo group. Does that means he cannot run sudo commands ?
Well, in fact, he can. But only for specific commands I allowed him to use sudo with.
To be honest, the “pihole” user has been put automatically in the “sudo” group during the Pihole installation. But, as this user will only be used for some specific action to manage the Pihole instance on my server, I preferred to removed him from the “sudo” group (using the gpasswd command) and filter what he can do with sudo myself (check the next chapter to learn more about that).
[pi@pihole ~]$ sudo gpasswd -d pihole sudo → remove the user “pihole” from the “sudo” group
The actual best way to check if your user has sudo permissions is to use the “sudo -l” command.
[pi@pihole ~]$ sudo -l Matching Defaults entries for pi on pihole : env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=NO_AT_BRIDGE, env_keep+="http_proxy HTTP_PROXY", env_keep+="https_proxy HTTPS_PROXY", env_keep+="ftp_proxy FTP_PROXY", env_keep+=RSYNC_PROXY, env_keep+="no_proxy NO_PROXY" User pi may run the following commands on pihole : (ALL : ALL) ALL pihole@pihole:~$ sudo -l Matching Defaults entries for pihole on pihole : env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=NO_AT_BRIDGE, env_keep+="http_proxy HTTP_PROXY", env_keep+="https_proxy HTTPS_PROXY", env_keep+="ftp_proxy FTP_PROXY", env_keep+=RSYNC_PROXY, env_keep+="no_proxy NO_PROXY" User pihole may run the following commands on pihole : (ALL) NOPASSWD: /home/pihole/pihole_FTL_log_management.sh, /home/pihole/pihole_log_management.sh, /home/pihole/pihole_update.sh, /home/pihole/pihole_blacklist_update.sh, /home/pihole/pihole_whitelist_update.sh
What we can see here, is that the “pi” user can run all commands with sudo, but the “pihole” user can only run the command specifically written (which are the scripts I wrote for the pihole instance management I’ve talked about before).
You can also see that the user “pihole” has a special attribute “NOPASSWD”. That means he can run the following commands with sudo without having to enter his password. More on that on the next point.
How to filter sudo permissions :
The sudo configuration is stored is the /etc/sudoers.d/ directory. But you shouldn’t add your various configurations directly in it (although it will work, that a risk of breaking it in case you added a wrong configuration).
The best way to add your own configuration is to use the “visudo” command. This command will allows you to modify the sudo configuration file and will check for potential errors before applying your new configuration.
In this file, you can add/delete/modify various parameters such as groups or users allowed to run sudo commands, specific ways of using sudo per groups/users, etc… Whether they are in the “sudo” group or not !
Before showing you how I configured it, let’s talk about the principles parameters you may need to know about :
You can apply a new sudo configuration to a specific user by typing its name or to an entire group by typing its name preceded by a “%” sign (like so : %name_of_the_group)
You can choose between 3 ways of using sudo, according to 3 different parameters :
– Blank (no parameter) → Sudo will ask for the user password when it will be used. That’s the default configuration.
– NOPASSWD: → Sudo will not ask for any password when it will be used. It might sounds weird, but it’s actually a really useful option for a particular case that I’ll show you below.
– ROOTPW: → Sudo will ask for the root password instead of the regular user password (It was hard for me to find a case where this was actually a good idea… But I guess, it can be useful if you want to give specific sudo rights to a user while keeping the control on it by typing the root password yourself each time the user needs to use sudo… Anyway, I prefer to give sudo permissions to users that really needs them or not giving them at all. Useless and risky option in my opinion).
You can then choose if the user or group can run all commands with sudo by typing “ALL” or specified a list of allowed commands separated by a comma.
Be aware that you can make several configurations for the same user or group, in order to mix those parameters if needed.
So here’s is my personal configuration :
[pi@pihole ~]$ sudo visudo # # This file MUST be edited with the 'visudo' command as root. # # Please consider adding local content in /etc/sudoers.d/ instead of # directly modifying this file. # # See the man page for details on how to write a sudoers file. # Defaults env_reset Defaults mail_badpass Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL:ALL) ALL # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # See sudoers(5) for more information on "#include" directives: #includedir /etc/sudoers.d pihole ALL=(ALL) NOPASSWD:/home/pihole/pihole_FTL_log_management.sh,/home/pihole/pihole_log_management.sh,/home/pihole/pihole_update.sh,/home/pihole/pihole_blacklist_update.sh,/home/pihole/pihole_whitelist_update.sh
I added the bold lines above. This way, the user pihole can run all the scripts I wrote to manage the Pihole instance with sudo but without having to type his password.
Why working with scripts instead of regular commands in visudo ? And why allowing sudo without password ? :
I highly recommend working with scripts (or aliases) instead of regular commands when it implies sudo rights. And there’s two reasons for that.
The first one is, like I said in my previous article, humans often fail… Machines don’t !
Like uncle Ben once said : “With great power comes great responsibility”. All of this to say that a mistyped command using sudo can be fatal for your system.
Executing sensitive commands via a script (or an alias) is a good way to avoid mistakes.
The second reason is that allowing commands directly into the sudo configuration might be very dangerous, depending on the way you’ve done it.
Let’s take an easy example :
In one of the scripts I wrote for the user “pihole” to manage pihole’s log files, I use the well-known and basic “find” command to get a list of the current pihole’s log files stored on my system.
Those files are stored in a directory in which the “pihole” user doesn’t have enough permissions to read those files. So this “find” command has to be executed with sudo rights.
Well okay, I’ll just give sudo rights for the “find” command to the “pihole” user using visudo, like so :
pihole ALL=(ALL) NOPASSWD:/usr/bin/find
Until you find that the not so basic “find” command is actually powerful enough to gain a root shell while being using with sudo :
[pi@pihole ~]$ sudo find . -exec /bin/sh \; -quit # whoami root # id uid=0(root) gid=0(root) groupes=0(root) # cd /root # pwd /root # ls -l total 4 -rw-r--r-- 1 root root 79 févr. 7 18:57 secret.txt # cat secret.txt How did you manage to read this ?! You shouldn't be able to read those lines ! #
Oops… You cannot imagine what “basic” commands are capable to do when executed with sudo rights…
So, the workaround would be to get more precise on the way to use the find command with sudo.
You can actually specify some flags for a command or a specific target (such as file, directory, etc…) :
pihole ALL=(ALL) NOPASSWD:/usr/bin/find /var/log/pihole/
So now, my “pihole” user can only run find with sudo on the /var/log/pihole/ directory, which is way better !
But, in some particular cases, it can be hard to be precise enough.
Maybe there’s 20 different directories/files that the user need to execute sudo on, maybe the log file contains the current date so it never has the same name, etc…
So, in my opinion, the best and cleanest way is to write a script that does everything that needs to be done and give sudo right only for this script to the user via “visudo”.
This way, he only gain sudo right when executing the script and only for what’s specifically written in it.
Don’t forget to make sure that the user cannot modify the script himself (“Permissions” chapter above 😉 ).
Okay, so now let’s answer the question “Why allowing sudo without password ?”.
The answer is really simple. Those scripts are meant to run through a crontab. It is a way to automate tasks on Linux by asking the system to run specific commands/scripts at a specific month/day/hour/minute.
I asked my system to run those scripts during the night via the crontab and, strangely, I don’t want to wake up every night to type my password while the system is executing those scripts… :p
So the NOPASSWD: option is really useful for that particular case !
That’s it for the sudo configuration. This is the most important part of this article in my opinion !
Deactivate login for users that does not need to be connected :
I tried my best for the “pihole” user to be autonomous. I wrote scripts that are running automatically and periodically via the crontab for each tasks he has to perform, I gave him sudo rights (without password) where he needed them so I do not need to interact myself and I asked him to send me reports about his different performed tasks via mail inside the scripts.
He acts as a service user and, unless he encountered an error, he doesn’t need my intervention at all. So let’s “deactivate” it !
I edited my /etc/passwd file to make the “pihole” user a “nologin” one, like so :
[pi@pihole ~]$ sudo vi /etc/passwd […] pihole:x:999:995::/home/pihole:/usr/sbin/nologin […]
My “pihole” user is not “logineable” anymore :
[pi@pihole ~]$ su - pihole Password : This account is currently not available.
And that actually make sense. This user has some sudo rights while executing scripts. Furthermore, I configured it to be self-dependant.
Letting a way to access to that account would be a big security threat as it is an open door that doesn’t need to be open.
If I ever need to access it for any reasons, I can just re-edit my /etc/passwd file like so :
[pi@pihole ~]$ sudo vi /etc/passwd […] pihole:x:999:995::/home/pihole:/bin/bash […]
But keep in mind that there’s no point of letting a user account accessible if there’s no particular needs for this. You can always make it accessible again if needed.
That was quite a lot of information there, so let’s sum up quickly.
The first thing you want to care about, is to make sure that each of your users have their own and strong password.
You may not want to use the root account directly to administrate your server. You’d better use a “regular” account with sudo rights for that. According to this, disable direct root connection over ssh is a good idea.
About permissions, I know that I’ve been quick on that point but I showed you what kind of permissions I usually use for sensitive file/script (chmod 750 with decent owner and group). Do not apply unnecessary permissions.
The most important part of this article to me is the sudo configuration. A misconfigured sudo can be a big security threat/concern for your server. Make sure that anyone running sudo has a need for it and do no hesitate to filter that usage if needed.
Also, even if it is situational, I showed you how to deactivate login for an account. It might be a good idea for users that run as “service user” and that doesn’t need anyone connected to work. As I said, if this door doesn’t need to be open, let’s close it !
And there you go, applying all of these basic configurations is already a decent security policy for your server 🙂
This is how I configured my Linux “Pihole” server in term of security. Hope you learned things that will help you improve your Linux servers security 😉
Bonus tip for people using Raspbian :
I found something really odd in the Raspbian installation… I assume (and hope) that this is specific to Raspbian.
There’s actually an extra file under the /etc/sudoers.d/ called “010_pi-nopasswd”.
This file allows the « pi » user to run any command with sudo without having to type his password. It seems to be created by default during the Raspbian installation, such as the « pi » user itself.
That is a big security threat/concern to me. It basically makes the default « pi » user acting like a normal root account, or sort of.
I find it insane to create such a file by default. Anyway, I strongly advise you to delete it so the system will ask for your password when using sudo with the « pi » user (just like it normally should) :
[pi@pihole ~]$ sudo rm /etc/sudoers.d/010_pi-nopasswd
Bye bye 🙂