Enabling MFA on an EC2 Instance with SELinux Enabled

Enabling MFA on an EC2 Instance with SELinux Enabled

Multi-factor authentication (MFA) provides an additional layer of security to your Amazon EC2 instances, ensuring that a user needs more than just a key or password to access a system. Instead, users are required to provide something they have, such as a code from an MFA device (e.g., Google Authenticator or Authy). When configuring MFA for SSH access to an EC2 instance running Amazon Linux, you can ensure that even if an attacker compromises an SSH key, they cannot log in without the MFA token.

In addition to MFA, you may have SELinux (Security-Enhanced Linux) enabled on your Amazon Linux instance. SELinux is a security mechanism that provides an additional layer of protection for the system by enforcing security policies that govern how processes interact with each other and the system’s files. Configuring MFA on an EC2 instance with SELinux enabled requires ensuring that the necessary security contexts and policies are properly configured to allow the MFA process to work alongside SELinux's protections.

In this guide, we will walk through the following steps:

  1. Setting up MFA on the EC2 instance for SSH login.

  2. Ensuring SELinux is properly configured to not interfere with the MFA process.

  3. Testing the MFA-enabled SSH login to ensure that access is secure and compliant with both MFA and SELinux policies.

Key Components for This Setup:

  1. Amazon EC2 Instance running Amazon Linux (or compatible version) with SELinux enabled.

  2. Virtual MFA device (such as Google Authenticator or Authy).

  3. SSH access configured for the EC2 instance.

  4. Sudo privileges on the EC2 instance to modify configurations.

  5. SELinux enabled and properly configured to allow necessary changes for MFA implementation.

Why You Need SELinux and MFA?

  • MFA: Protects against unauthorized access by requiring users to provide not only their SSH key but also a time-sensitive code from a registered MFA device.

  • SELinux: Provides an additional security layer, ensuring that processes and access to files are controlled by enforcing strict security policies. In this case, SELinux will need to be configured to allow any necessary modifications for enabling MFA.

By the end of this guide, you'll have successfully implemented MFA for SSH access to your Amazon Linux EC2 instance, with SELinux configured to support the changes without breaking the system’s security context. This will significantly enhance your instance's overall security, making unauthorized access much more difficult.

Step 1: Installing Google Authenticator on the EC2 Instance

First, SSH into your EC2 instance. Once connected, switch to the root user (or use sudo for administrative tasks) and install the necessary software packages.

  1. Install Google Authenticator and QRencode:

    Run the following commands to install the Google Authenticator PAM module and qrencode (for generating QR codes):

     sudo dnf install google-authenticator qrencode -y
    
  2. Initialize Google Authenticator:

    Run the google-authenticator command for the user for whom you want to enable MFA (e.g., ec2-user). This command will generate a secret key and provide a QR code to scan with the Google Authenticator app.

     google-authenticator -s ~/.ssh/google_authenticator
    

    When setting up Google Authenticator on your EC2 instance, you’ll be prompted with several configuration questions to customize how the MFA (Multi-Factor Authentication) will work. These options allow you to fine-tune the behaviour of the authentication process, balancing between security and usability. Here's a more detailed breakdown of each of these prompts:

    Do you want authentication tokens to be time-based?

    Prompt:

     Do you want authentication tokens to be time-based? (y/n)
    
    • Time-based tokens are the default method used by Google Authenticator and most MFA apps. These tokens expire after a short period (typically 30 seconds), and a new token is generated for the next window. The time-based mechanism ensures that even if someone intercepts a token, they can't use it later.

    • Recommendation: Yes (y) is the recommended choice because time-based tokens offer better security. They are regularly rotated, minimizing the risk of token reuse or interception.

The process will display a QR code for you to scan, or you can manually enter the secret key into your authentication app to register your device. Add your account name to the app and enable the time-based option. It's important to store the secret key, verification codes securely, and scratch codes generated during the process in case you lose access to the app on your device. Remember, each scratch code can only be used once.

Instead of manually entering the key, we will be scanning the QR code.

Next, You'll be prompted with several questions to configure MFA:

a. Do you want me to update your "/home/ec2-user/.ssh/.google_authenticator" file? (y/n)

When you configure Google Authenticator for Multi-Factor Authentication (MFA) on your EC2 instance, one of the prompts you will encounter is:

    Do you want me to update your "/home/ec2-user/.ssh/.google_authenticator" file (y/n)?

This is an important step in the setup process because the .google_authenticator file contains critical information related to your MFA configuration, including the secret key used to generate time-based One-Time Passwords (OTPs) and the scratch codes you’ll use if you lose access to the MFA app.

b . Do you want to disallow multiple uses of the same authentication token?

Prompt:

    Do you want to disallow multiple uses of the same authentication token? (y/n)
  • If you choose Yes (y), each authentication token will only be valid for a single login attempt. This means that once you enter a token and successfully log in, the token is invalidated and cannot be reused, even if the same token is entered again.

  • Disallowing multiple uses of the same token provides an additional layer of security. In case a malicious actor intercepts a token during transmission, they won't be able to reuse it for another login attempt, even if they manage to access the server or your session.

  • Recommendation: Yes (y) is recommended because it prevents the token from being reused by attackers, which is a useful security measure. It forces attackers to generate a new token for each login attempt, reducing the chances of successful brute-force attacks.

c . Do you want to increase the time window for valid tokens (default is 1:30 min)?

Prompt:

    Do you want to increase the time window for valid tokens (default is 1:30 min)? (y/n)
  • This option allows you to extend the time window in which a generated authentication token is valid. By default, Google Authenticator tokens are valid for 30 seconds (the "1:30 min" refers to the 1 minute 30 seconds time window, which includes the current 30-second token and the previous and next 30-second tokens to accommodate any time skew between the client and server).

  • Increasing the time window (e.g., to 4 minutes) could be helpful if you're experiencing issues with time synchronization between the client (your phone or device) and the server, especially if you are in a region with unstable or variable network conditions. However, the downside is that extending the window makes it easier for attackers to guess the token, as they have more time to try to authenticate.

  • Recommendation: No (n) is generally the best choice. The default 1:30-minute window is usually sufficient and provides a good balance of security and usability. Extending the window should only be considered if you're facing issues with time drift or synchronization.

d . Do you want to enable rate-limiting for login attempts?

Prompt:

    Do you want to enable rate-limiting for login attempts? (y/n)
  • Rate-limiting helps prevent brute-force attacks by limiting the number of login attempts a user can make within a specific time frame. If enabled, the system will allow only a certain number of authentication attempts (e.g., 3 attempts) within a defined period (e.g., 30 seconds). After this limit is reached, further attempts will be blocked temporarily.

  • Recommendation: Yes (y) is the recommended option. Enabling rate-limiting is a simple but effective way to reduce the chances of a successful brute-force attack. If an attacker tries to guess the token by repeatedly entering incorrect values, the system will block them after a few failed attempts, making it much harder for them to break into the system.

These configuration options are all about finding the balance between security and usability. By opting for the recommended settings, you will significantly improve the security of your EC2 instance while minimizing the risk of unauthorized access via brute force or token reuse.

After these options, the tool will display a QR code in your terminal. You can scan this code with the Google Authenticator app or manually enter the provided secret key.

  1. Restore the SELinux context for the new configuration:

    Since we have SELinux enabled, we need to restore the proper security context for the .google_authenticator file:

     restorecon -Rv ~/.ssh/
    

Step 2: Configure PAM (Pluggable Authentication Module) for MFA

The next step is to modify the PAM configuration to enable Google Authenticator for SSH logins. We’ll update the PAM configuration file (/etc/pam.d/sshd) to require Google Authenticator's second-factor authentication.

  1. Edit the PAM configuration file:

    Open the PAM configuration file for SSH (/etc/pam.d/sshd) with a text editor:

     sudo nano /etc/pam.d/sshd
    

    Add the following line at the bottom of the file to enable Google Authenticator for MFA:

     auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator
     auth required pam_permit.so
    

    Alternatively, if you want to allow some users to bypass MFA, you can add the nullok option to the end of the line:

     auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator nullok
     auth required pam_permit.so
    

    Note: nullok will allow users who haven't set up MFA to log in without a second-factor prompt.

  2. Comment out the password authentication line:

    In the same file (/etc/pam.d/sshd), find the line that references password-auth and comment it out to ensure only SSH key-based authentication and MFA are required:

     #auth substack password-auth
    

Step 3: Update SSH Configuration to Require MFA

Next, we need to update the SSH server configuration (/etc/ssh/sshd_config) to require both an SSH key and a verification code.

  1. Edit the SSH configuration file:

    Open the SSH configuration file with a text editor:

     sudo nano /etc/ssh/sshd_config
    
  2. Make the following changes:

    • Disable the interactive keyboard authentication:

      Comment out the line:

        #KbdInteractiveAuthentication yes
        KbdInteractiveAuthentication yes
      
    • Enable Challenge-Response Authentication:

      Uncomment or add the following line:

        ChallengeResponseAuthentication yes
      
    • Enable the Authentication Methods:

      Add this line at the bottom of the file:

        AuthenticationMethods publickey,keyboard-interactive
      
  3. Restart the SSH service:

    After saving the changes, restart the SSH service for the changes to take effect:

     sudo systemctl restart sshd.service
    

Step 4: Test the MFA Setup

To verify that everything is working, open a new terminal and attempt to SSH into your EC2 instance. After entering your SSH key passphrase (if applicable), you will be prompted to enter a verification code generated by the Google Authenticator app.

Example prompt:

Verification code:

Enter the code from the Google Authenticator app. If successful, you should be logged in. If unsuccessful, ensure your system time is synchronized correctly, as Google Authenticator relies on time-based codes.

Step 5: Force Users to Set Up Google Authenticator on First Login

If you want to enforce the MFA setup for all users upon their first login, you can create a script that will automatically prompt users to set up Google Authenticator if they haven’t done so already.

  1. Create a script to enforce MFA setup:

    Create a new file in the /etc/profile.d/ directory:

     sudo nano /etc/profile.d/mfa.sh
    

    Paste the following script into the file:

     if [ ! -e ~/.ssh/google_authenticator ] && [ "$USER" != "root" ]; then
         google-authenticator -s ~/.ssh/google_authenticator
         restorecon -Rv ~/.ssh/
         echo "Save the generated emergency scratch codes and use the secret key or scan the QR code to register your device for multifactor authentication."
         echo "Login again using your ssh key pair and the generated One-Time Password on your registered device."
         echo "logout"
     fi
    
  2. Set the correct permissions for the script:

    Set the script file’s permissions to make it readable for all users:

     sudo chmod o+r /etc/profile.d/mfa.sh
    
  3. Update PAM configuration:

    Update the PAM configuration for SSH (/etc/pam.d/sshd) to run the MFA setup script on user login:

     auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator nullok
    

Remove nullok After MFA Setup

Once all users have configured MFA, you can remove the nullok option from the PAM configuration file to ensure that users must use MFA for all future logins.

  1. Edit the PAM configuration again:

     sudo nano /etc/pam.d/sshd
    
  2. Remove nullok from the line that includes pam_google_authenticator.so:

     auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator
    
  3. Save and exit.

Conclusion

By following these steps, you’ve successfully configured Multi-Factor Authentication (MFA) on your Amazon EC2 instance running Amazon Linux 2023. This setup enhances security by requiring users to authenticate with both an SSH key and a time-based OTP generated by the Google Authenticator app.

Additionally, with SELinux correctly configured, you’ve ensured that security policies are maintained without disrupting the MFA functionality. Lastly, by forcing users to set up MFA on their first login, you can ensure that every user accessing your EC2 instance has MFA enabled, further bolstering your instance’s security.