Build Your Own Two Factor Authentication Server

I was recently working with Horizon View and VMware Identity Manager in a lab environment. To recreate a specific issue, I needed to enable two-factor authentication. I found a great article describing how to setup RADIUS with Google Authenticator to make this happen (https://blogs.vmware.com/consulting/files/2015/02/VMW_15Q1_TD_Horizon-View-Google-Authenticator_021715_FINAL_EMonjoin.pdf). Unfortunately I ran into a few issues, most likely because I was trying to use a newer version of Ubuntu. I wanted to document the updated steps in case I need to recreate this configuration in the future.

To start, I deployed an Ubuntu 16.04.1 template and joined it to Active Directory. For those steps, you can check out this post: http://enterpriseadmins.org/blog/virtualization/lab-template-ubuntu-16-04/.

VM in hand, and joined to Active Directory, I installed the RADIUS and Google Authenticator modules:

apt-get install libpam-google-authenticator freeradius -y

I then changed the radiusd.conf file to all the user and group to be root for this process. This is needed as Google Authenticator requires the .google_authenticator file created later to only be readable by the user. Running this process as root allows the radius process to read these files as well.

nano /etc/freeradius/radiusd.conf

Find the lines that state user=freerad and group=freerad. Update each to look like:

user=root
group=root

We now update the users authorized to use Free RADIUS. We reject requests from users in a specific group, and then tell FreeRADIUS to use PAM for all other authentications. We do this by removing some comments, and adding a line in the freeradius/users file:

nano /etc/freeradius/users
DEFAULT Group == "lab_radius_disabled", Auth-Type := Reject
Reply-Message = "Your account has been disabled."
DEFAULT Auth-Type := PAM

We now need to update a file to enable pluggable authentication modules in free RADIUS. Note: to find text using nano, you can use CTRL+W.

nano /etc/freeradius/sites-enabled/default

When we find the text for #PAM, remove the pound sign to enable PAM.

The default PAM RADIUS config only expects a password. Since we want to use our Google Auth code, we need to make a few changes.

nano /etc/pam.d/radiusd

Comment out the @include lines in the file, then add the following text:

auth requisite pam_google_authenticator.so forward_pass
account required pam_unix.so use_first_pass

Now we need to define which clients can use our RADIUS server, and what their ‘secret’ will be. It is common to restrict this so only specific hosts can access RADIUS, and each server can have a unique secret. However, for my lab, I’m going to allow all servers to connect to RADIUS using the same secret. We do this by editing this file:

nano /etc/freeradius/clients.conf

And adding a client entry like this one:

client 192.168.0.0/16 {
        secret          = s3cur3.rad
        shortname       = PrimaryLabSubnet
}

Note –  alphanumeric and _-+.  (underscore hyphen plus period) are the supported characters for this secret (from https://support.software.dell.com/kb/154463

Now that we have all of the configuration files edited, we can restart the freeradius service:

service freeradius restart

You are almost there…

Users will need to login (SSH) to our RADIUS server to generate their specific Google Authenticator key. This only needs to happen once (unless they need to regenerate their unique key). By default, a user can just enter ‘google-authenticator’, answer half a dozen questions, and will get a QR code for their unique key.

google-auth-0-capture

To ensure that each user answers these questions the same, lets pre-answer them… by creating an alias for all new users. To save a few characters, we’ll shorten this alias to google-auth.

nano /etc/skel/.bashrc

Now we scroll down to where the other aliases are and add one of our own:

alias google-auth='google-authenticator -tdf -l "$USER Home Lab" -r 3 -R 30 -w 17 -Q ANSI'

This file will automatically be copied to the .bashrc folder for all newly created profiles. If you’ve already logged into your Linux box and want this handy alias, you can edit your personal /home/username/.bashrc file, or just copy the default .bashrc for new users into your profile, like this:

cp /etc/skel/.bashrc /home/bwuchner/.bashrc

Option #1, new users
The first time a user logs in, they will need to create a unique key for their account. To do this, they simply type

google-auth

and lanuch the quick alias we just made. This will generate a QR code they can use to add the account to their mobile device.

google-auth-1-capture

Option #2, existing users
I have several labs, each with their own RADIUS servers. Instead of having a unique key per lab, I re-use my Google Authenticator key across environments — don’t tell my info-security team 🙂

To do this, I just need to copy the contents of /home/bwuchner/.google_authenticator to other RADIUS servers. Since this file only contains simple text, I pass it into a text editor over SSH.

nano .google_authenticator

We add our key text, which looks like this:

A2ANXSELX3KIS5DD
"RATE_LIMIT 3 30
" WINDOW_SIZE 17
" DISALLOW_REUSE
" TOTP_AUTH
52311114
79666855
35676886
84689191
97921843

Note: In the real world you’d like to be much more security conscious of this text, as it represents the ‘something you have’ factor of authentication. Anyone who knows this text can easily impersonate you.

The file must be readable only by the current user, so change permissions with:

chmod 400 ~/.google_authenticator

Thats it! We can now test that everything is working using radtest. Here is simple syntax, assuming my username is bwuchner, password is P@ssw0rd, RADIUS server is 192.168.0.100 and RADIUS secret is s3cur3.rad:

radtest bwuchner 'P@ssw0rd442287' 192.168.0.100 1812 s3cur3.rad

The response should show Access-Accept. If you get something else, like Access-Reject, then check /var/log/auth.log to see what went wrong. I find that it is easiest to have two SSH sessions opened — one running radtest and the other running

tail -f /var/log/auth.log

Good luck, I hope this helps make your lab authentications more secure!

Lab template: CentOS 7.2

Recently I’ve been working in a couple of different / disconnected labs. This means I’m managing a couple copies of all my templates manually. Sometimes its hard to find the right section of my notes depending on when/where I’m working on the lab, so I decided to post a couple quick blog posts so I can always find them. The following notes are for creating a template based on CentOS 7.2, and include notes on setting a static IP and joining to the domain with pbis-open (formerly likewise-open).

Special thanks to http://www.tecmint.com/things-to-do-after-minimal-rhel-centos-7-installation/… which showed me how to get ifconfig in my minimal install. I’m not sure who decides what makes the cut for minimal installations, but ifconfig and nslookup seem like they should be in to me.

Install CentOS 7.2 Minimal install from ISO image (http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso), accepting all defaults. Create an administrator account named hostadmin during the install.

Once the install is complete, login as hostadmin. Switch to root and set a password for the root user.

sudo su -
passwd

In my testing, the VM did not get an IP address from DHCP, even though DHCP was available and working. To get online I had to change ONBOOT=no to ONBOOT=yes in the file:

vi /etc/sysconfig/network-scripts/ifcfg-eno16777984

I then restarted networking to bring the interface back up with an IP:

service network restart

Now that I have an IP, I update/upgrade my installation and install some handy/useful packages:

yum update && yum upgrade
yum install net-tools bind-utils nano ntp wget -y

Get the template ready for PowerBroker Identity Services (formerly likewise-open) domain joins:

rpm --import http://repo.pbis.beyondtrust.com/yum/RPM-GPG-KEY-pbis
wget -O /etc/yum.repos.d/pbiso.repo http://repo.pbis.beyondtrust.com/yum/pbiso.repo
yum clean all
yum install pbis-open

At this point, I shutdown the VM and convert it to a template. When I’m ready to use the VM, I deploy a copy from template and follow the remaining steps.

If needed, set a static IP by updating the following file… this is the same file we edited earlier to enable DHCP:

nano /etc/sysconfig/network-scripts/ifcfg-eno16777984

For Static IP, remove bootproto=dhcp, and add the following

IPADDR="192.168.0.101"
PREFIX="24"
GATEWAY="192.168.0.1"
DNS1="192.168.0.20"
SEARCH="lab.enterpriseadmins.org"

Verify that the hostname is properly set:

nano /etc/hostname

Join the Linux VM to the domain and create a DNS record:

domainjoin-cli join lab.enterpriseadmins.org adminbw
/opt/pbis/bin/config AssumeDefaultDomain true
/opt/pbis/bin/config LoginShellTemplate /bin/bash
/opt/pbis/bin/config HomeDirTemplate %H/%U
/opt/pbis/bin/config RequireMembershipOf "lab\\domain^users"
/opt/pbis/bin/update-dns

Once I reach this point, I kick off a quick reboot (just to make sure the domain join took) and am now free to use the VM.

Lab template: Ubuntu 16.04

Recently I’ve been working in a couple of different / disconnected labs. This means I’m managing a couple copies of all my templates manually. Sometimes its hard to find the right section of my notes depending on when/where I’m working on the lab, so I decided to post a couple quick blog posts so I can always find them. The following notes are for creating a template based on Ubuntu 16.04.1, and include notes on setting a static IP and joining to the domain with pbis-open (formerly likewise-open).

Install Ubuntu 16.04.1 Server from ISO image (http://www.ubuntu.com/download/server/thank-you?version=16.04.1&architecture=amd64), accepting all defaults. When prompted for an admin user, use the name hostadmin.

Once the install is complete, login as hostadmin. Switch to root and set a password for the root user.

sudo su -
passwd

Apply updates and install the packages openssh-server and ntp:

apt-get update && apt-get upgrade
apt-get install openssh-server ntp -y

Get the template ready for PowerBroker Identity Services (formerly likewise-open) domain joins:

wget http://download1.beyondtrust.com/Technical-Support/Downloads/PowerBroker-Identity-Services-Open-Edition/pbiso/850/pbis-open-8.5.0.153.linux.x86_64.deb.sh
chmod +x pbis-open-8.5.0.153.linux.x86_64.deb.sh
./pbis-open-8.5.0.153.linux.x86_64.deb.sh
cd /opt/pbis/bin/ 

At this point, I shutdown the VM and convert it to a template. When I’m ready to use the VM, I deploy a copy from template and follow the remaining steps.

If needed, set a static IP by updating the following file:

nano /etc/network/interfaces

The important sections to include in the iface settings are address, netmask, gateway, dns-search, and dns-nameservers. An example has been included below:

iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1
dns-search lab.enterpriseadmins.org
dns-nameservers 192.168.0.20

Verify that the hostname is properly set:

nano /etc/hostname

Join the Linux VM to the domain and create a DNS record:

domainjoin-cli join lab.enterpriseadmins.org adminbw
/opt/pbis/bin/config AssumeDefaultDomain true
/opt/pbis/bin/config LoginShellTemplate /bin/bash
/opt/pbis/bin/config HomeDirTemplate %H/%U
/opt/pbis/bin/config RequireMembershipOf "lab\\domain^users"
/opt/pbis/bin/update-dns

Once I reach this point, I kick off a quick reboot (just to make sure the domain join took) and am now free to use the VM.

Reload syslog configuration on ESXi

I recently updated Log Insight to version 3.3.2 in my lab. After selecting the appropriate PAK file, the UI displayed a warning containing the following text:

Note that certain builds of ESXi need to have 
their syslog configuration reloaded after restart, 
otherwise log data will stop forwarding. 
Configuration can be reloaded from the vSphere 
Integration page. See the Online Help for 
more information.

I waited a couple hours after the upgrade to check back on the system and noticed that I was no longer collecting syslog data. I visited the vSphere Integration page and reviewed my hosts, but they were already configured as expected. I picked just one host and updated the configuration anyway, and that host started logging data again. For another host, I manually cleared the syslog.global.logHost value from the web client and then re-entered the logHost text. This also caused the host to start sending syslog data again. Interested in the minimum effort to ‘reload’ syslog configuration (without needing to update/reset logHost values) I found the following KB article: https://kb.vmware.com/kb/2003322. It appears that esxcli has an option to simply reload the configuration (using esxcli system syslog reload). To run this on all hosts remaining in my inventory, I executed the following code:

1
2
3
4
Get-VMHost | Sort-Object Name | %{
write-host -nonewline "$($_.Name) reloading syslog:"
(Get-EsxCli -VMHost $($_.Name) -v2).system.syslog.reload.invoke()
}

Note: this requires the latest version (6.3 release 1) of PowerCLI. I hope someone finds this information helpful.

Find ESXi Installation Date with PowerCLI

I recently noticed a link to a very interesting article on Twitter: Find ESXi Installation Date — http://vcdx56.com/2016/01/05/find-esxi-installation-date/. These steps are straight forward and show how to calculate the original ESXi install date, looking at the first section of the UUID. I didn’t realize so much useful information was coded into the UUID, but this could be useful information for certain reports. To understand the process, please check out the original article on vcdx56.com.

The following few lines of code will return this information for all hosts in a vCenter using PowerCLI.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Find ESXi install date: http://vcdx56.com/2016/01/05/find-esxi-installation-date/
# Convert HEX to DEC: http://michaelflanakin.com/Weblog/tabid/142/articleType/ArticleView/articleId/1073/Converting-ToFrom-Hex-with-PowerShell.aspx
# Convert epoch to date: http://stackoverflow.com/questions/10781697/convert-unix-time-with-powershell

Get-VMHost | Sort Name | %{
  $thisUUID = (Get-EsxCli -VMHost $_.name).system.uuid.get()
  $decDate = [Convert]::ToInt32($thisUUID.Split("-")[0], 16)
  $installDate = [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($decDate))
  [pscustomobject][ordered]@{
    Name="$($_.name)"
    InstallDate=$installDate
  } # end custom object
} # end host loop