Read about how to apply multi-factor authentication on Linux (servers), to sleep better even though you know your server is publicly available

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

  1. Update package lists

    sudo apt-get update

  2. 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.

  1. Connect via SSH

    ssh root@111.11.11.11
    root@111.11.11.11 password:

  2. 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]

  3. Add the user to sudoers

    usermod -aG sudo codespecialist

  4. 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.


  5. Test logging in

    ssh codespecialist@111.11.11.11

    You should be able to login with the credentials you just created.


  6. Disable the root login

    Open the sshd_config

    sudo nano /etc/ssh/sshd_config

    find the PermitRootLogin entry and change it to no

    # Authentication:
    ...
    PermitRootLogin no
    ...

  7. Restart the SSHD service

    sudo systemctl restart sshd

  8. 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)

  1. Install UFW

    sudo apt-get install ufw

  2. Add SSH firewall rule

    Allow ssh connections, either by applying sudo ufw allow ssh or sudo 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.


  3. 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.

  1. [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 files

    ssh-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]-----+

  2. 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.

  3. 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

  4. Disable password authentication

    Edit your sshd_config and change the PasswordAuthentication from yes to no

    sudo nano /etc/ssh/sshd_config
    ...
    PasswordAuthentication no
    ...

  5. Restart the SSHD service

    sudo systemctl restart sshd

  6. 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.

  1. Install the google authenticator

    sudo apt-get install libpam-google-authenticator

  2. 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.


  3. 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

  4. Adjust the SSHD config

    There are several things in the config you have to change or assure this time:

    • ChallengeResponseAuthentication is set to yes
    • UsePAM is set to yes
    • AuthenticationMethods is set to publickey,keyboard-interactive
    ...
    ChallengeResponseAuthentication yes
    ...
    UsePAM yes
    ...
    AuthenticationMethods publickey,keyboard-interactive

  5. Restart the SSHD service

    sudo systemctl restart sshd

  6. 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.