Multi-factor authentication is all around us nowadays. And for a good reason, single layers of authentication are easily compromised by leaked credentials, exposed keys or even third party security leaks.
However, there is no reason to get paranoid. Two or at most three are enough when it comes to layers of authentication. The risk of locking out yourself increases with each layer and restoring gets trickier too.
Also, various layers of authentication do not necessarily mean your server is more secure each layer may be a vulnerability itself if not choosen wisely.
I usually use two layers:
- SSH-Key
- Time-based one-time Password (TOTP)
In the following three sections we're going through basic security measures and how to configure your server to apply SSH-Key and TOTP (Google Authenticator) based authentication. But first of all we start with some basic security measures.
Information
In this example we're going to assume you use Ubuntu 20.04, but most
concepts are easy to adjust to various operating systems and require only
slight to none changes using another ubuntu version.
This is a practical how-to, we assume you know about the basics.
Be careful when changeing security related settings. You may easily
lock yourself out or even create vulnerabilities if you lack proper knowledge
of what you're doing. Do not apply anything blindly.
To lessen the chance of a full lock out, you might want to keep a second ssh session
connected at all time while applying the steps below.
Basic Security
Your auth layers are basically useless if they're exorbitantly vulnerable. The least you should do, is to make sure everything is up to date, disable the root login and configure a basic firewall.
Update
First thing you should do when configuring a new Linux server, is to update the packages
-
Update package lists
sudo apt-get update
-
Upgrade the packages
sudo apt-get upgrade -y
Deactivate Root Login
One thing you really should do as your second action when configuring a new server, is to disable the root user or atleast prohibit login with it. The root is simply to mighty and a leak of its credentials is your servers armageddon.
-
Connect via SSH
ssh root@111.11.11.11 root@111.11.11.11 password:
-
Create a new user
sudo adduser codespecialist
Shell output
Adding user `codespecialist' ... Adding new group `codespecialist' (1000) ... Adding new user `codespecialist' (1000) with group `codespecialist' ... Creating home directory `/home/codespecialist' ... Copying files from `/etc/skel' ... New password: Retype new password: passwd: password updated successfully Changing the user information for codespecialist Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n]
-
Add the user to sudoers
usermod -aG sudo codespecialist
-
Switch and check permissions
su codespecialist sudo ls
Shell output
codespecialist@ubuntu:~$ sudo ls [sudo] password for codespecialist: codespecialist@ubuntu:~$
If the sudo command succeeds, then you have been successfully aded to the sudoers.
-
Test logging in
ssh codespecialist@111.11.11.11
You should be able to login with the credentials you just created.
-
Disable the root login
Open the
sshd_config
sudo nano /etc/ssh/sshd_config
find the
PermitRootLogin
entry and change it tono
# Authentication: ... PermitRootLogin no ...
-
Restart the SSHD service
sudo systemctl restart sshd
-
Test it
Open a second terminal and try to connect as root
ssh root@111.11.11.11
Shell output
root@111.11.11.11's password: Permission denied, please try again
Set up a Firewall
To restrict access from and to ports, you might want to add a basic firewall. One firewall widely used is the Uncomplicated Firewall (UFW)
-
Install UFW
sudo apt-get install ufw
-
Add SSH firewall rule
Allow ssh connections, either by applying
sudo ufw allow ssh
orsudo ufw allow 22
.sudo ufw allow ssh
Shell output
[sudo] password for codespecialist: Rules updated Rules updated (v6)
Make sure this step proceeds by checking the output. Else, you might lock out yourself and exstinguish any chance to restore the server as well.
-
Enable the firewall
sudo ufw enable
When you use the
ufw enable
command, UFW will be started, and also registered as a service started on system startup.
Authenticate using a SSH-Key
Using a SSH-Key is an easy way to improve security without increasing the number of manually provided credentials. All you have to do is configure your local ssh-agent and provide your public key to the machine your want to secure. You need to apply the following steps on your local machine.
Information
This section requires you to have installed openshh-client. This should be preinstalled on most operating systems. But you might have to find a work-arround when using Windows.
-
[Optional] Create a SSH-Key
If you do not have a ssh key yet, you can create a new one. It's possibly a good choice to add a comment with
-C
to allocate it correctly later on. Follow the instructions given by the CLI. Also, make sure not to loose the private key created in this step. Its also recommended you use a passphrase in order for the key to be encrypted with AES-CBC instead of lying arround as plain text filesssh-keygen -t ed25519 -C "codespecialist@111.11.11.11"
Shell output
ssh-keygen -t ed25519 -C "codespecialist@111.11.11.11" Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/codespecialist/.ssh/id_ed25519): /Users/codespecialist/.ssh/codespecialist Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/codespecialist/.ssh/codespecialist Your public key has been saved in /Users/codespecialist/.ssh/codespecialist.pub The key fingerprint is: SHA256:ggejZWoZgOYJL4epj/IkvL34z0T3Var+GBS6K93kiTo codespecialist@111.11.11.11 The key's randomart image is: +--[ED25519 256]--+ |o | |oo | |+=. = . . | |=.oB + . . + | |.o= ..ooS. o | |o. ....+.o | |.+. ...=+. | |oo= oE oo+o | |.+o+o++. o.. | +----[SHA256]-----+
-
Add the key to the server
ssh-copy-id -i ~/.ssh/codespecialist codespecialist@111.11.11.11
Shell output
ssh-copy-id -i /Users/codespecialist/.ssh/codespecialist codespecialist@111.11.11.11 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/codespecialist/.ssh/codespecialist.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys codespecialist@111.11.11.11's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'codespecialist@111.11.11.11'" and check to make sure that only the key(s) you wanted were added.
-
Check if the key was added correctly on the remote host
cat ~/.ssh/authorized_keys
Shell output
ssh-ed25519 AAAAC3NzaC2lZDI1NTE5AAAAIMdM36AX6tY/+vnPSQ4JLB20SP2ANU7js8uBnIzlQHFf codespecialist@111.11.11.11
-
Disable password authentication
Edit your
sshd_config
and change thePasswordAuthentication
fromyes
tono
sudo nano /etc/ssh/sshd_config
... PasswordAuthentication no ...
-
Restart the SSHD service
sudo systemctl restart sshd
-
Login using the SSH-Key
Logging in without password should now be possible, but at the same time, only your SSH-Key will be accepted from now on.
ssh -i ~/.ssh/codespecialist codespecialist@111.11.11.11
Authenticate using the Google-Authenticator
Now that we have a decent authentication mechanism and some basic security features, lets add a second layer to the authentication.
Information
Make sure you are logged in to the remote host with the user you want to use in future, as the google authenticator is only configured for this specific user.
Also, please open a second SSH connection to the server and keep it open until you're sure, the google autenticator is working properly. Otherwise you might lock out yourself with a single misconfiguration.
-
Install the google authenticator
sudo apt-get install libpam-google-authenticator
-
Run the google authenticator script
Once you followed the steps of the google authenticator, a QR-code will be generated in the shell, that you can scan with an authenticator app on your smartphone, tablet or whatever. Just make sure, its not your local machine, as the authentication layer is horribly ineffective against attackers compormising your local machine.
google-authenticator
Shell output
Do you want authentication tokens to be time-based (y/n) y Warning: pasting the following URL into your browser exposes the OTP secret to Google: Your new secret key is: G2URAC442DYGBIJDCDHY2HTFNM Your verification code is 221804 Your emergency scratch codes are: 25690887 90233439 52851954 71051205 30624510 Do you want me to update your "/home/codespecialist/.google_authenticator" file? (y/n) y Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n) y If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n) y
Make sure to write down these scratch codes, as they are the only thing that may help you, if you loose or damage your device with the TOTP-App.
-
Add the google authenticator as a auth factor
sudo nano /etc/pam.d/sshd
Search for the
@include common-auth
line which should be at the very beginning and comment it out.#@include common-auth
Add the authenticator module at the bottom of the file
auth required pam_google_authenticator.so
-
Adjust the SSHD config
There are several things in the config you have to change or assure this time:
ChallengeResponseAuthentication
is set toyes
UsePAM
is set toyes
AuthenticationMethods
is set topublickey,keyboard-interactive
... ChallengeResponseAuthentication yes ... UsePAM yes ... AuthenticationMethods publickey,keyboard-interactive
-
Restart the SSHD service
sudo systemctl restart sshd
-
Test it
When try you open a new ssh session with the server, it is going to ask for a verification code, which should accept the one your TOTP app displays.
ssh -i .ssh/codespecialist codespecialist@111.11.11.11
Shell output
(codespecialist@111.11.11.11) Verification code:
Congratulations!
Your remote host is now a bit more secure, and the likelyhood of you being a victim of bruteforce attacks significantly lower. If you are interested in further ways to improve security, system hardening is the topic to look into next.
If you encounter any issues please comment below, so we can provide a solution and improve this article.