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.11root@111.11.11.11 password:
-
Create a new user
sudo adduser codespecialistShell 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 successfullyChanging the user information for codespecialistEnter the new value, or press ENTER for the defaultFull 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 codespecialistsudo lsShell 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.11You should be able to login with the credentials you just created.
-
Disable the root login
Open the
sshd_config
sudo nano /etc/ssh/sshd_configfind 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 sshShell output
[sudo] password for codespecialist:Rules updatedRules 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 enableWhen 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/codespecialistEnter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /Users/codespecialist/.ssh/codespecialistYour public key has been saved in /Users/codespecialist/.ssh/codespecialist.pubThe key fingerprint is:SHA256:ggejZWoZgOYJL4epj/IkvL34z0T3Var+GBS6K93kiTo codespecialist@111.11.11.11The 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.11Shell 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 keyscodespecialist@111.11.11.11's password:Number of key(s) added: 1Now 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_keysShell 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-authenticatorShell output
Do you want authentication tokens to be time-based (y/n) yWarning: pasting the following URL into your browser exposes the OTP secret to Google:Your new secret key is: G2URAC442DYGBIJDCDHY2HTFNMYour verification code is 221804Your emergency scratch codes are:2569088790233439528519547105120530624510Do you want me to update your "/home/codespecialist/.google_authenticator" file? (y/n) yDo you want to disallow multiple uses of the same authenticationtoken? This restricts you to one login about every 30s, but it increasesyour chances to notice or even prevent man-in-the-middle attacks (y/n) yBy 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 atime skew of up to 30 seconds between authentication server and client. If youexperience problems with poor time synchronization, you can increase the windowfrom its default size of 3 permitted codes (one previous code, the currentcode, the next code) to 17 permitted codes (the 8 previous codes, the currentcode, and the 8 next codes). This will permit for a time skew of up to 4 minutesbetween client and server.Do you want to do so? (y/n) yIf the computer that you are logging into isn't hardened against brute-forcelogin 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) yMake 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/sshdSearch for the
@include common-auth
line which should be at the very beginning and comment it out.#@include common-authAdd 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.11Shell 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.