Recently, I was logging into my AWS account, where I have multi-factor authentication (MFA) enabled, using the Google Authenticator application on my smart phone. This inspired me to research how to enable MFA for any Linux distribution. I ran across the following blog entries:
- Three-factor authentication with OpenSSH, Google Authenticator and Password | Today I learnt
- How to Secure SSH with Google Authenticator’s Two-Factor Authentication | How-To Geek
From there, I figured I would try to create a Eucalyptus EMI that would support three-factor authentication on a Eucalyptus 4.0 cloud. The trick here was to figure out how to display the Google Authenticator information so users could configure Google Authenticator. The euca2ools command ‘euca-get-console-output‘ proved to be the perfect mechanism to provide this information to the cloud user. This blog will show how to configure an Ubuntu Trusty (14.04) Cloud image to support three-factor authentication.
Prerequisites
In order to leverage the steps mentioned in this blog, the following is needed:
- Ubuntu Trusty (14.04) Cloud Image
- Eucalyptus 4.0 Cloud
- Euca2ools 3.1 (due to the use of euca-install-image)
- The IAM permissions mentioned in Prerequisites section one of my previous blog entries – “CoreOS CloudInit Config for Docker Storage Management“
Now that the prereqs have been mentioned, lets get started.
Updating the Ubuntu Image
Before we can update the Ubuntu image, let’s download the image:
[root@odc-f-13 ~]# wget http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
After the image has been downloaded successfully, the image needs to be converted to a raw format. Use qemu-img for this conversion:
[root@odc-f-13 ~]# qemu-img convert -O raw trusty-server-cloudimg-amd64-disk1.img trusty-server-cloudimg-amd64-disk1.raw
After converting the image to a raw format, we need to mount it in order to update the image accordingly:
[root@odc-f-13 ~]# losetup /dev/loop0 trusty-server-cloudimg-amd64-disk1.raw [root@odc-f-13 ~]# kpartx -av /dev/loop0 add map loop0p1 (253:2): 0 4192256 linear /dev/loop0 2048 [root@odc-f-13 ~]# mkdir /mnt/ubuntu [root@odc-f-13 ~]# mount /dev/mapper/loop0p1 /mnt/ubuntu [root@odc-f-13 ~]# chroot /mnt/ubuntu
The above command ‘chroot’ allows us to edit the image as if its the current running Linux operating system. We have to install a couple of packages in the image. Before we do, use the resolvconf to create the necessary information in /etc/resolv.conf.
root@odc-f-13:/# resolvconf -I
Confirm the settings are correct by running ‘apt-get update’:
root@odc-f-13:/# apt-get update
Once that command runs successfully, install the PAM module for Google Authenticator and the whois package:
root@odc-f-13:/# apt-get install libpam-google-authenticator whois
After these packages have been installed, run the ‘google-authenticator’ command to see all the available options:
root@odc-f-13:/# google-authenticator --help google-authenticator [<options>] -h, --help Print this message -c, --counter-based Set up counter-based (HOTP) verification -t, --time-based Set up time-based (TOTP) verification -d, --disallow-reuse Disallow reuse of previously used TOTP tokens -D, --allow-reuse Allow reuse of previously used TOTP tokens -f, --force Write file without first confirming with user -l, --label=<label> Override the default label in "otpauth://" URL -q, --quiet Quiet mode -Q, --qr-mode={NONE,ANSI,UTF8} -r, --rate-limit=N Limit logins to N per every M seconds -R, --rate-time=M Limit logins to N per every M seconds -u, --no-rate-limit Disable rate-limiting -s, --secret=<file> Specify a non-standard file location -w, --window-size=W Set window of concurrently valid codes -W, --minimal-window Disable window of concurrently valid codes
Updating PAM configuration
Next the PAM configuration file /etc/pam.d/common-auth needs to be updated. Find the following line in that file:
auth[success=1 default=ignore]pam_unix.so nullok_secure
Replace it with the following lines:
auth requisite pam_unix.so nullok_secure auth requisite pam_google_authenticator.so auth [success=1 default=ignore] pam_permit.so
Next, we need to update SSHD configuration.
Update SSHD configuration
We need to modify the /etc/ssh/sshd_config file to help make sure the Google Authenticator PAM module works successfully. Modify/add the following lines to the /etc/ssh/sshd_config file:
ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive
Updating Cloud-Init Configuration
The next modification involves enabling the ‘ubuntu‘ user to have a password. By default, the account is locked (i.e. doesn’t have a password assigned) in the cloud-init configuration file. For this exercise, we will enable it, and assign a password. Just like the old Ubuntu Cloud images, we will assign the ‘ubuntu‘ user the password ‘ubuntu‘.
Use ‘mkpasswd‘ as mentioned in the cloud-init documentation to create the password for the user:
root@odc-f-13:/# mkpasswd --method=SHA-512 Password: $6$8/.y8gwYT$dVmtT7jXdBrz0w1ku5mh6HOC.vngjsXpehyeEicJT4kIyhvUMV3p9VGUIDC42Z1mjXdfAaQkINcCfcFe5jEKX/
In the file /etc/cloud/cloud.cfg, find the section ‘default_user‘. Change the following line from:
lock_passwd: True
to
lock_passwd: False passwd: $6$8/.y8gwYT$dVmtT7jXdBrz0w1ku5mh6HOC.vngjsXpehyeEicJT4kIyhvUMV3p9VGUIDC42Z1mjXdfAaQkINcCfcFe5jEKX/
The value for the ‘passwd‘ option is the output from the mkpasswd command executed earlier.
Updating /etc/rc.local
The final update to the image is to add some bash code to the /etc/rc.local file. The reason for this update is so the information for configuring Google Authenticator with the instance can be presented to the user through the output of ‘euca-get-console-output‘. Add the following code to the /etc/rc.local file above the ‘exit 0‘ line:
if [ ! -f /home/ubuntu/.google_authenticator ]; then /bin/su ubuntu -c "google-authenticator -t -d -f -r 3 -R 30 -w 4" > /root/google-auth.txt echo "############################################################" echo "Google Authenticator Information:" echo "############################################################" cat /root/google-auth.txt echo "############################################################" fi
Thats it! Now we need to bundle, upload and register the image.
Bundle, Upload and Register the Image
Since we are using an HVM image, we don’t have to worry about the kernel and ramdisk. We can just bundle, upload and register the image. To do so, use the euca-install-image command. Before we do that, we need to exit out of the chroot environment and unmount the image:
root@odc-f-13:/# exit [root@odc-f-13 ~]# umount /mnt/ubuntu [root@odc-f-13 ~]# kpartx -dv /dev/loop0 del devmap : loop0p1 [root@odc-f-13 ~]# losetup -d /dev/loop0
After unmounting the image, bundle, upload and register the image with the euca-install-image command:
[root@odc-f-13 ~]# euca-install-image -b ubuntu-trusty-server-google-auth-x86_64-hvm -i trusty-server-cloudimg-amd64-disk1.raw --virtualization-type hvm -n trusty-server-google-auth -r x86_64 /var/tmp/bundle-Q8yit1/trusty-server-cloudimg-amd64-disk1.raw.manifest.xml 100% |===============| 7.38 kB 3.13 kB/s Time: 0:00:02 IMAGE emi-FF439CBA
After the image is registered, launch the instance with a keypair that has been created using the ‘euca-create-keypair‘ command:
[root@odc-f-13 ~]# euca-run-instances -k account1-user01 -t m1.medium emi-FF439CBA RESERVATION r-B79E6A59 408396244283 default INSTANCE i-48D98090 emi-FF439CBA pending account1-user01 0 m1.medium 2014-07-21T20:23:10.285Z ViciousLiesAndDangerousRumors monitoring-disabled 0.0.0.0 0.0.0.0 instance-store hvm sg-A5133B59
Once the instance has reached the ‘running’ state, use ‘euca-get-console-ouptut’ to grab the Google Authenticator information:
[root@odc-f-13 ~]# euca-describe-instances i-48D98090 RESERVATION r-B79E6A59 408396244283 default INSTANCE i-48D98090 emi-FF439CBA euca-10-104-6-237.bigboi.acme.eucalyptus-systems.com euca-172-18-238-157.bigboi.internal running account1-user01 0 m1.medium 2014-07-21T20:23:10.285Z ViciousLiesAndDangerousRumors monitoring-disabled 10.104.6.237 172.18.238.157 instance-store hvm sg-A5133B59 [root@odc-f-13 ~]# euca-get-console-output i-48D98090 ....... ############################################################ Google Authenticator Information: ############################################################ https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/ubuntu@euca-172-18-238-157%3Fsecret%3D2MGKGDZTFLVE5LCX Your new secret key is: 2MGKGDZTFLVE5LCX Your verification code is 275414 Your emergency scratch codes are: 59078604 17425999 89676696 65201554 14740079 ############################################################ .....
Now we are ready to test access to the instance.
Testing Access to the Instance
To test access to the instance, make sure the Google Authenticator application is installed on your smart phone/hand-held device. Next, copy the URL seen in the output (e.g. https://www.google.com/chart?chs=200×200&chld=M|0&cht=qr&chl=otpauth://totp/ubuntu@euca-172-18-238-157%3Fsecret%3D2MGKGDZTFLVE5LCX) from ‘euca-get-console-output’, and past it into a browser:

Use the ‘Google Authenticator’ application on your smart phone/hand-held device, and scan the QR Code:


After selecting the ‘Set up account‘ option, select ‘Scan a barcode‘, hold your smartphone/hand-held device to the screen where your browser is showing the QR code, and scan:

After scanning the QR code, you should see the account get added, and the verification codes begin to populate for the account:

Finally, SSH into the instance using the following:
- the private key of the keypair used when launching the instance with euca-run-instances
- the password ‘ubuntu‘
- the verification code displayed in Google Authenticator for the new account added
With the information above, the SSH authentication should look similar to the following:
[root@odc-f-13 ~]# ssh -i account1-user01/account1-user01.priv ubuntu@euca-10-104-6-237.bigboi.acme.eucalyptus-systems.com The authenticity of host 'euca-10-104-6-237.bigboi.acme.eucalyptus-systems.com (10.104.6.237)' can't be established. RSA key fingerprint is c9:37:18:66:e3:ee:66:d2:8a:ac:a4:21:a6:84:92:08. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'euca-10-104-6-237.bigboi.acme.eucalyptus-systems.com,10.104.6.237' (RSA) to the list of known hosts. Authenticated with partial success. Password: Verification code: Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-32-generic x86_64) * Documentation: https://help.ubuntu.com/ System information as of Mon Jul 21 13:23:48 UTC 2014 System load: 0.0 Memory usage: 5% Processes: 68 Usage of /: 56.1% of 1.32GB Swap usage: 0% Users logged in: 0 Graph this data and manage this system at: https://landscape.canonical.com/ Get cloud support with Ubuntu Advantage Cloud Guest: http://www.ubuntu.com/business/services/cloud 0 packages can be updated. 0 updates are security updates. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. ubuntu@euca-172-18-238-157:~$
Three-factor authentication has been successfully configured for the Ubuntu cloud image. If cloud administrators would like to use different authentication for the instance user, I suggest investigating how to set up PAM LDAP authentication, where SSH public keys are stored in OpenLDAP. In order to do this, the Ubuntu image would have to be updated to work. I would check out the ‘sss_ssh_authorizedkeys‘ command, and the pam-script module to potentially help get this working.
Enjoy!