A key component of the AWS shared security model is the capability to secure remote access to your Amazon EC2 instances. In the case of Linux servers, remote access usually means establishing a connection to the server by using the SSH protocol. Authentication typically happens either by providing a user name and password or by providing a private key that is checked against a public key on the server. By default, most Amazon EC2 instances use the latter approach for user authentication: when you first launch an EC2 instance, you are asked to optionally assign it a key pair. AWS uses the user name along with the PEM file that is associated with the key pair to authenticate with the server and open an SSH session.
When you create an EC2 instance you are prompted to create or select a previously-created key pair for the instance so that you can SSH into the box. That key pair is downloaded and stays on your local machine. The risk here is if your local machine is compromised. Then, any user who has this key pair and the username now has full access to your instances. In order to make access to the instances more secure to help prevent a breach, you should put additional controls. One of the best-recommended practices, when it comes to AWS console access, is to have multi-factor authentication (MFA) enabled for the root account and all user accounts.
Two-factor authentication, or multi-factor authentication (MFA), requires a user to provide multiple proofs of identity to get access to a resource. For example, you can configure access to the AWS Management Console to require users to enter a user name and password in addition to a rotating code from a hardware or software MFA device. This approach is also increasingly used to add an extra layer of security for access to servers and workstations, where a private key or a user name/password must be provided in addition to an authentication code from an MFA device before a session is opened on the operating system.
We recommend limiting the access to your instances to a bastion host, so that people can’t violate the security policy by logging directly into the instances. This can be done by creating an inbound rule of type SSH in the security group of those instances, with the source being either the IP or the security group of the bastion host. Once you have done that, you can focus on tightening the security on your bastion host and only putting your controls there. One other benefit is that you don’t need to have MFA enabled on each instance. You can enable MFA only on the bastion host, and if you want you can have another prompt for another one-time password (OTP) when you run SSH command to log into another instance from the bastion host.
Google Authenticator implements the TOTP algorithm from RFC 6238. When you install the Google Authenticator application on your Amazon EC2 instance, AWS generates a secret key. This secret key is then shared with a second device of your choice, such as an application running on your mobile phone. The exchange of the secret key usually happens when you use the mobile application to scan a QR code generated by Google Authenticator.
Once the secret key is stored in the mobile application, it combines it with the current timestamp by using a cryptographic hash function to generate one-time passwords (OTPs). An OTP is the second authentication factor that you will be prompted to input after successfully authenticating by using a user name and password or PEM file. The OTP is difficult to compromise because it auto-rotates as time passes, usually every 30 seconds, and is generated by using a device that you usually keep with you at all times (such as your phone).
Two-factor authentication for Amazon Linux with Google Authentication and AWS MFA
Linux uses PAM (Pluggable Authentication Module) to integrate the Google Authenticator MFA. So make sure that PAM and PAM-Devel packages are installed on your system. If not, please install them.
SSH into your EC2 instance the way you normally would and then switch into your root account or use sudo and run:
yum install pam.x86_64 yum install pam-devel.x86_64
Add the EPEL (Extra Packages for Enterprise Linux) repo.
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
Install Google Authenticator:
# sudo yum install google-authenticator -y
Once the package is installed, run the initialization app to generate a key for the user you are logged in as (e.g. ec2-user) to add second-factor authentication to that user account.
Run the initialization app:
You will be asked if the authentication tokens used should be time-based. In this example, we will use time-based tokens.
[ec2-user@ip-172-31-87-234 ~]$ google-authenticator Do you want authentication tokens to be time-based (y/n) y
This will generate a URL which will have a QR code that you should scan using your Google Authenticator app, or manually enter the secret key in your app to register your device. Add your account name in the app, and make sure that the time-based option is enabled. Save the secret key, verification code, and scratch codes generated on the instance in a secure place for use if you lose access to the app on the registered device. Each scratch code can be used only once.
Now download Google authenticator application on your Mobile phone and scan the QR code in URL link and register the token
Next, you will be asked if the google_authenticator file should be updated for user ‘ec2-user.’ Typing ‘y’ will save the secret key, scratch codes, and the other configuration options you select later on in the file. You will run the initialization app and go through the same procedure for each user account to enable MFA on each account.
Do you want me to update your "/home/ec2-user/.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) n 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
Configure SSH to use the Google Pluggable Authentication Module
Run the following command to make changes to the PAM configuration.
sudo vi /etc/pam.d/sshd
Add the following to the bottom of the file to use Google Authenticator. If there are service accounts or users who should be able to log in without MFA, add nullok at the end of the following statement. This will mean that users who don’t run Google Authenticator initialization won’t be asked for a second authentication.
auth required pam_sepermit.so auth required pam_google_authenticator.so auth required pam_google_authenticator.so nullok
Comment out the password requirement. We just want to use the key pair and the verification code generated on the Google Authenticator app.
#auth substack password-auth
Save the file. Next, we need to change the SSH configuration to make it prompt for a second authentication.
sudo vi /etc/ssh/sshd_config
Comment out the line which says ChallengeResponseAuthentication ‘no’ and uncomment the line which says ‘yes’.
ChallengeResponseAuthentication yes #ChallengeResponseAuthentication no
Lastly, we need to let SSH know that it should ask for SSH key and a verification code to let us in. At the bottom of the file add:
Save the file. Restart the SSH to let the changes take effect.
sudo service sshd restart
To test if it’s working, open a new terminal window and SSH into the instance and you will be asked for a verification code.
Type the code that’s generated on your Google Authenticator app.
There are a few ways you can make multi-factor authentication possible for your users.
Log into the new user accounts after you create them, run the initialization app, and then share the generated keys and scratch codes specific to that user. This way you won’t have to share the same secret key with others. When the user leaves, all you have to do is delete that user account.
The most secure approach would be to force users to run the initialization app on their first log in and save the key and the scratch codes generated. This could be done by running a script on logins.
Automating copying SSH key to new user accounts and forcing users to enable MFA on the first login
When we create new users, the first thing we do is copy the authorized_key file to the new user account and change its permissions appropriately so that the user can use the same key pair and successfully SSH into the instance. The best practice is to create a separate key pair for each user.
Open the authorized_keys file cat ~/.ssh/authorized_keys and copy the public key. We will use this later to create a similar file in a new user account. The public key will look like:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6Vhz2ItxCih+PnDS Uaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXrlsLnBItntckiJ7FbtxJM XLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZqaeJAAHco+CY/5WrUBkrHmFJr6 HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3RbBQoQzd8v7yeb7OzlPnWOyN0qFU0XA246 RA8QFYiCNYwI3f05p6KLxEXAMPLE
Create a new user:
sudo adduser newuser sudo su - newuser mkdir .ssh chmod 700 .ssh touch .ssh/authorized_keys chmod 600 .ssh/authorized_keys
Paste the public key copied before in:
The above copying process can be automated for all users if you create the file and the directory structure .ssh/authorized_keys in /etc/skel/ directory. Once you do that, the new users created will automatically have these files available in their home directory with proper permissions.
You can also run the following command before creating the users to do what we did above, and the users will be able to log in using their key pair.
To force users to configure MFA on their first login, switch to the root user and create a file mfa.sh in /etc/profile.d/ directory and paste the following script in it.
if [ ! -e ~/.google_authenticator ] && [ $USER != "root" ]; then google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=3 echo echo "Save the generated emergency scratch codes and use secret key or scan the QR code to register your device for multifactor authentication." echo echo "Login again using your ssh key pair and the generated One-Time Password on your registered device." echo logout fi
You can remove the condition for $USER != “root” if you want a prompt for a second-factor authentication when you switch to the root user.
At the bottom of the file /etc/pam.d/sshd, it should have the following statement for the above script to run when users log in.
auth required pam_google_authenticator.so nullok
Delete the old user account :
sudo userdel -r olduser
By correctly implementing two-factor authentication for your Amazon EC2 Linux hosts, you can reduce risk and significantly increase security.