What do you think this is?

just thoughts of a restless mind...

Securing administrative access with MFA

Securing administrative access with MFA

Now that multi factor authentication is gaining ground I thought I would write a simple guide on how to secure administrative access with MFA on Linux systems. The solution is simple and based on Google Authenticator. The good thing with Google Authenticator is that it’s a typical TOTP/HOTP solution and as such does not require any internet connectivity on either the server or the client.
The configuration examples provided are more or less appropriate for openSUSE Leap 15 and Ubuntu 18.04 LTS

I assume you know how to set up Google Authenticator on Linux. Most of the time it’s just something like “apt install libpam-google-authenticator” (on Ubuntu) or “zypper in google-authenticator-libpam” (on openSUSE). After you install it, you need to run -as every user- the command google-authenticator to generate the seed and configuration. Then you add this seed to your mobile phone’s Authenticator app of choise (such as Google Authenticator for either Android or iPhone. At this point you have set up and working the ability to use one time passwords - but they are not used anywhere yet.

In this article I will focus on which services we need to modify in order to securely protect privileged access.

If you have more than a few servers and a few users, I suggest investing in a proper IAM solution. Having said that, the design I provide should be compatible with all IAM products. You may opt to use it if they don’t have a similar design on their own or if you want to avoid their suggestion (such as sharing keys and passwords between users which I find a terrible idea).

This design can easily be part of a centralized configuration management solution such as Puppet, Ansible, Chef or Salt, CFEngine and SUSE Manager.
Beware: storing the seeds and recovery codes as plaintext in a central location means that your central repository becomes super critical - if it wasn’t considered such already. Make sure you include that information in your threat model.

Why secure administrative access

According to an article from 2016 the misuse of privileged credentials was involved in 80% of data breaches. That number only went down to 74% recently. I believe that is enough of a reason to secure your privileged access. Actually almost all the solutions around Identity and Access Management focus specifically on this - the protection of privileged access. There may be different approaches and thoughts about what privileged credentials are, but as I’m talking about Linux here the idea is to protect the root account.

Do we also secure non-administrative access?

There is a simple question many people ask: Why not enable multi-factor authentication always and for everything? Although multi-factor authentication has significant advantages over single factor, it’s not always necessary. Imagine this simple scenario: You connect to your network through VPN and from there you can only get into a bastion host before you login to a server - as an unauthorized user. I cannot help but wonder: How many OTPs will you use, and with how many different seeds? And how confident are you that you won’t lock yourself out if you use different seeds? Again, it’s about your threat model. If a threat scenario is that your MFA seed is stolen, you may ask for an OTP at every other command without improving your security the tiniest bit!

I always suggest having strong access control while keeping things reasonable and operations usable. You may -as an example- skip MFA on console logins, provided that you have proper physical access control. I for one, setup my SSH access with two options:

  • I can login using public key authentication as a single and only factor. My key is password protected as it should, and is actually stored on a smart card
  • I can login using PAM which mandates multi factor authentication with a combination of password and an OTP provided by Google Authenticator

I believe these two options are more or less equally (and in my case, adequately) secure.

PAM Configuration for MFA mandate

When we installed the google authenticator binary, we installed a PAM module as well. This Google Authenticator PAM module provides functionality only for authentication. In most Linux distributions I’m familiar with, there is a common-auth file which defines the common authentication functionality. This common file is then included in all (or most) service files. Simply meaning, if we want to enable MFA globally we need to make our changes on this common-auth file.

My suggestion though is to not enable it globally. As it requires a per user set up, you may break things such as su for example. A global enablement will apply to the root user as well and this is not something we want at this point. We do want to protect the root user, and we will do, but not by enabling MFA globally.
I also suggest you start enabling Google Authenticator in specific services after all your physical users have initialized it for their use.

Useful PAM details

PAM modules works in a stackable way. One may add several modules and depending on their control method the authentication is considered successful or not. There are four 4 different controls:

  • sufficient: if the module succeeds then that’s enough, you are authenticated. If the module fails, PAM moves on to try other modules
  • optional: if this module is set up alongside others then it’s actually ignored. If it’s the only method set up, then its result defines success or failure.
  • requisite: if the module fails, authentication fails immediately. No other modules after that are even tried.
  • required: if the module fails, authentication fails. But not immediately. PAM will move on to try all the other set up modules. That is the preferred options for MFA setup. First you check the user’s password. No matter if it succeeds or not, you move on and try the OTP. This makes the google-authenticator pam module work as Multi Factor authentication and not Two Step Verification.

Some other MFA implementations (cough MS-O365 cough) only request the OTP after successfully confirming the user’s password. This setup actually gives a potential attacker the opportunity to work on cracking the password first before moving to solving the OTP issue. It also enables potential attackers to perform a DOS by trying different passwords on different users and locking your users out.

Using PAM you can avoid the first problem and mitigate the second by configuring the control as required. The attacker is thus forced to guess and/or crack/bypass both authentication factors at the same time because there is no information if one of them is correct

SSH

Considering you have initialized Google Authenticator for the users as per the documentation, you need to enable it. In the file /etc/pam.d/ssh add after all other auth lines, the entry (in one single line):

auth required pam_google_authenticator.so

I assume that your common-auth file is included in the ssh PAM file and that it contains pam_unix.so (true for both openSUSE and Ubuntu).

Configure sshd appropriately. In the /etc/ssh/sshd_config file you should have (among others) the following entries:

PasswordAuthentication no
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey keyboard-interactive:pam

In an essence, this is how this ends up:

This configuration allows either single-factor public key authentication or PAM based authentication which we just set up to be multi-factor.

SU, SUDO and Configuration changes

If you want to use su to switch to root you may, but then you’re running into issues with the Google Authenticator seed. As Google Authenticator would require root’s OTP to be provided, it means that you need to provide the seed of the root account to all your administrators - something that I don’t advise.

Instead I suggest you disable the root account (as Ubuntu already does) and use sudo for performing administrative tasks. There is no limitation and if you want to revert to a su like functionality you may simply sudo -i. The difference here is that sudo does not authenticate root, it authenticates the invoking user. That is the default configuration and although you may change it, I suggest you leave it as it is.
In that case Google Authenticator will require the user’s OTP, so every user will just provide their own OTP.

sudo is significantly more flexible and configurable than su. It can provide fine-grained access control and has one additional benefit: it has a parameter called timestamp_timeout which defines for how long will sudo remember that the user is authorized. This, if configured properly, can actually minimize the annoyance of constant asking for an OTP.

The problem with using sudo though with the default configuration of Google Authentication is that if the account gets compromised and the attacker is already in the system as unprivileged user, they can read the seed from the .google_authenticator file itself and generate an OTP with nothing stopping them.

To the rescue, Google Authenticator module has an option that was designed for encrypted home directories but works nicely in this case too. You can have the users’ .google_authenticator files somewhere else than their home directories, and not even readable by the users themselves.

I suggest moving these files to a directory under /etc (let’s call the directory /etc/gaseeds) which will be root-owned. The permissions need to be 0600.

To do that you need to change the configuration of Google Authenticator and add two parameters: the path and the owner. This change has to be implemented in all the services you have set up to use Google Authenticator. The new entry should be (in one single line):

auth required pam_google_authenticator.so user=root secret=etc/gaseeds${USER}/.google_authenticator

Bonus side effect; any user who has not setup Google Authenticator will not be able to sudo before they set it up and an authorized user moves their .google_authenticator file in the appropriate directory. Although we can control sudoers from the appropriate file, an extra control mechanism doesn’t hurt.

Conclusion

What I describe can be set up in less than 5 minutes. What we managed to do in these 5 minutes is to ensure that we enforce MFA for privileged access. The steps were:

  • Allow single-factor public key authentication to SSH
  • If that fails, request multi-factor password+OTP combination for SSH
  • Allow the authorized users to sudo with their password+OTP combination
  • Ensure that the OTP seeds are only readable by root

Using a proper configuration management tool you can push this configuration to all Linux servers in your environment and use the same Google Authenticator App to login and sudo to root on all of them.

Thoughts and improvements are welcome.

Tagged in : linux, security, access control, two-factor authentication