First Steps for Securing Your Server
Written on 2021-04-16 by Unicorn
On a freshly installed system, there are a few steps we need to take to harden it and finish its basic setup. At this point we can only connect to our server via VNC (in the case of a VPS) or with a physical display, mouse and keyboard. Additionally, we currently only have the "root" account for managing the system, but we would like to use SSH and a separate admin account for the future.
Before you read
This guide assumes some basic understanding of how to use a terminal and what some symbols like "$", "#" and "~" mean, just to name a few examples. If you are not familiar with these, you can have a look at this guide that tries to cover some of these fundamentals:
I also strongly suggest any beginner to install and read the documentation of the commands that we will use. To learn the basics about finding and reading documentation, you can read this:
Lastly, if you find anything confusing or incorrect or otherwise have questions or suggestions, please send an email to email@example.com!
Step 1 - Creating and using an admin account
Creating a regular user account
Now, the real first step is to create a new user that I chose to call "admin", which we will use to manage the system from now onwards. I will also create an "admin" group alongside it, in case you want to have several accounts with administrative capabilities. That way you can just add them all to the "admin" group and they would be able to use root privileges with "doas".
First, we will create the "admin" group with "addgroup":
# addgroup admin
Now that we have created the group, let's create the "admin" user and add it to the group:
# adduser -h /home/admin -g 'Administrator' -G admin admin
"-h /home/admin" sets the home directory, "-g 'Administrator'" sets the description of the user to "Administrator", "-G admin" adds the user to the "admin" group and finally "admin" is the name of the user. To learn more about the commands, you can have a look at the different options and their explanations by executing "adduser" and "addgroup" without any additional options.
Setting up "doas"
"doas" is similar to "sudo", which you might be familiar with from other Linux and BSD systems. Essentially, it allows users to execute commands as a different user, for example "root", without being logged in through their account.
The reason why we use it instead of the more well-known "sudo" is its simplicity, both in terms of the size and complexity of its codebase and in the simplicity of its configuration. Less code with simpler logic means less room for bugs, while a simpler configuration means that we will have an easier time understanding how to securely configure our system for our purposes.
Just like "sudo", "doas" allows you to create rules that determine which users or groups can use which commands as which other users. For now, we will just allow all users in the "admin" group to execute commands as any other user, including "root".
We use "apk add" to install the package "doas", as well as its manual pages, which are contained in the package "doas-doc":
# apk add doas doas-doc
Now that "doas" is installed, let's configure it. The config file is located at "/etc/doas.conf". You can edit it with the editor "vi" that is already part of the system, or you can install an editor like "nano" that is a little more beginner friendly. As this is out of scope for this guide, please use a search engine to learn about how to use any of these editors. For this guide, we will stick to "vi":
# vi /etc/doas.conf
In the configuration file we simply insert "permit keepenv :admin". This means that any users in the "admin" group are allowed to use doas as any user with any command. "keepenv" means that the environment variables of the admin user are kept even when executing something as another user, for example root.
If we leave it at that, "doas" will work, though we have to type in our user's password each time we use it. To make this a little less painful, you can add the option "persist" (after the "permit" keyword), which makes "doas" remember if you recently typed in the password already and doesn't ask you again for a while. You may even consider using the "nopass" option, which means "doas" would not prompt you for a password at all. You can decide for yourself which option you are most comfortable with.
For other config options, you can read the manual with "man doas.conf". For usage of the "doas" command, consult "man doas". We will also go over more specific rules for other users in later guides.
Your "/etc/doas.conf" should now look something like this:
# see doas.conf(5) for configuration details # Uncomment to allow group "wheel" to become root # permit persist :wheel permit persist keepenv :admin
Now we can log in to the "admin" account with SSH to see if it works!
Step 2 - Setting up and using SSH
First login - Verifying the host key
From our home computer, let's log in to our server:
$ ssh admin@your_server
Of course, replace "your_server" with the IP Address or domain name of your server. Now, before you do anything, there will be a prompt that we should not disregard. This is what it would look like for the server that is currently hosting this website:
$ ssh firstname.lastname@example.org The authenticity of host 'regrow.earth (220.127.116.11)' can't be established. ECDSA key fingerprint is SHA256:EcaPUY1ufw3XDFH/rBTLOK2ILgwp76CWrBZEOyuMwqM. Are you sure you want to continue connecting (yes/no/[fingerprint])?
Before we mindlessly type "yes" to get on with our business, we should verify that the abovementioned ECDSA key fingerprint actually matches the fingerprint of the host key on our server. On our server, we use this command to show the fingerprint of the ECDSA host key:
# ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key 256 SHA256:EcaPUY1ufw3XDFH/rBTLOK2ILgwp76CWrBZEOyuMwqM email@example.com (ECDSA)
As the output shows, the fingerprint matches and we can proceed by typing "yes". This way, we know that nothing is intercepting our connection with the server and it is the foundation of SSH being able to securely connect to it and correctly identify it in the future.
IF THE KEY DID NOT MATCH, make sure that you checked the right key. In this case, it showed me the "ECDSA key fingerprint", but it could also show an RSA or ED25519 key fingerprint. Depending on what the prompt says, you'll have to check the right key in "/etc/ssh". If it still does not match, which will rarely happen (if ever), somebody is compromising your connection.
If all went well, everything matched and you typed "yes". You will then be prompted for the password of the "admin" account that we configured earlier and will then be logged in as the admin user.
Now we can verify whether doas works by using "doas -s". The "-s" option switches us into a shell of the specified user. If no user is specified, "doas" assumes that we want "root" privileges. It should look something like this, though you will be prompted for your password unless you use the "nopass" option in "doas.conf".
$ doas -s /home/admin #
As we can see by the "#" symbol, we are now in a shell with root privileges, without logging in as "root". Success! We can return to the shell of our admin user by typing "exit".
Securing SSH by using public keys
For the benefit of both security and convenience, we want to use public key authentication instead of passwords for logging in to our server. On our home computer, we can generate a keypair with the command "ssh-keygen":
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/unicorn/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/unicorn/.ssh/id_rsa Your public key has been saved in /home/unicorn/.ssh/id_rsa.pub The key fingerprint is: SHA256:avZhcMGPyi/a/TbI/7iBboJN4adB4H6iJTxW2kyT4ks unicorn@homecomputer The key's randomart image is: +---[RSA 3072]----+ | | | . . | | . o o | | . * o + | | o O +..S . | | E *.==.. | | o * **=+.. | | o .+=*+.oo | | ...+=+=+. | +----[SHA256]-----+
You can just press enter at every prompt for the keypair to be stored in its default location and without an additional password. An additional password would make it more secure, but then you'd have to type in a password again when using SSH.
Then, we need to copy the public key of our home computer to the server, so that the server knows that we are indeed who we claim to be. For this purpose, we create the ".ssh" directory in our "admin" user's home directory and then insert the public key into a file called "authorized_keys". Any public key that you put in this file will be able to log in to the "admin" account over SSH.
$ mkdir /home/admin/.ssh $ vi /home/admin/.ssh/authorized_keys
The default location of the public key of your home computer is "~/.ssh/id_rsa.pub". You can view it with "cat ~/.ssh/id_rsa.pub" and then copy the text into the "authorized_keys" file on the server.
Now try to log into your server with SSH again. If all has gone well, you no longer need to use your password. If you do get a password prompt, something has gone wrong and you should double check that the contents of the "authorized_keys" file on the server contain an exact copy of the "id_rsa.pub" on your home computer. Make sure that there are no accidental linebreaks in there!
Disabling SSH "root" login and password authentication
Now that we have an "admin" account with functioning public key authentication and the ability to execute commands as "root" by using "doas", we can turn off the ability to log in to the "root" user directly over SSH and disable password authentication. The configuration file of the SSH daemon is "/etc/ssh/sshd_config" and we will add three lines to it. The default settings in that file are commented out with a "#" in front of them, and we write our change below each original value so that we can always see what was the default. I will only show the three relevant parameters to keep the list short.
First, disabling "root" login:
#PermitRootLogin prohibit-password PermitRootLogin no
Secondly, disabling password authentication:
#PasswordAuthentication yes PasswordAuthentication no
#ChallengeResponseAuthentication yes ChallengeResponseAuthentication no
Then reload the SSH daemon to apply the changes:
$ doas rc-service sshd reload
Now we will only be able to log in to non-root accounts, and only with public key authentication. To verify this, you can try logging in to your server from your home computer without a public key, like this:
$ ssh admin@your_server -o PubkeyAuthentication=no
Your server should deny you access with a message saying "Permission denied (publickey)" if all is configured correctly:
$ ssh firstname.lastname@example.org -o PubkeyAuthentication=no email@example.com: Permission denied (publickey).
Disabling the "root" account
Since we will now be managing our system exclusively with the admin account, let's lock the root account down completely. This command edits the file "/etc/shadow", in which all the encrypted user passwords are stored. The command puts a "!" in front of the encrypted password, which makes it impossible for any password to match.
$ doas passwd -l root
You can verify that it is locked by checking the status:
$ doas passwd -S root
In the second column, it should show "L", which indicates that the password is locked.
For more information on the passwd command, check out its manpage!
Setting a new admin password
Now that we have encrypted terminal access to our server with SSH, let's also set a new password for the admin user:
And we are done!
We have practically replaced our root user with an admin user and used "doas" to allow it to manage the system from here onward. SSH lets us securely and conveniently access our server, and we additionally hardened it by disallowing root login and enforcing public key authentication. We now have a solid foundation on which we can set up whatever we wish to do.
To continue, here are some links to our other guides that build on this one:
As mentioned at the start, if you have any questions or suggestions, don't hesitate to email me at firstname.lastname@example.org!