The Background
I had a customer approach me over a year ago with a problem around a web application they use for monitoring patient telemetry in ICUs. The application was a rich media web application that on Windows was proving to be unstable and routinely was causing problems for them. They had tried multiple browsers, Windows versions, backend changes, and were finding no way to stabilize the system.
We had spoken with them previously about how IGEL functions and the robustness of our solution and how it can be catered to most workloads and function in ways to be rock solid. The customer remembered this and brought up if we could replace this use case of running this web application in a way that promoted the stability they needed.
After engaging with the customer and the vender, we determined the crux of the issue was simply that the application had been written to specifically function with IE only and using AD integrated authentication. The hospital system has hundreds of machines deployed attached to large screen monitors in ICUs for live patient data at all times. Quickly, the customer determined that even though they had already rolled these out, the solution required more client stability and there was no competing technology available to replace it with.
I met with the customer and the vender’s development team to scope and propose an alternate solution. Leverage a Linux endpoint using a mainline modern browser and an authentication standard designed for current web architectures and frameworks (aka, IGEL OS, Chrom[e/ium], and Kerberos). The vender raised concerns about how this could work and the fact that they had built their solution to be Windows Integrated Authentication and IE only. Since I was speaking to their developers, I asked some details around their platform and we got into the weeds. Over time, we, jointly, integrated a new authentication framework into their Node.js application stack. For the techies, it was moved from node-sspi (Integrated Windows Authentication Only [NTLM]) to node-expose-sspi (NTLM and Kerberos).
Having sorted their limited authentication components and proving that Kerberos authentication was now possible, we set out to build the framework for automation and completeness of the endpoint solution.
Currently, the customer has begun rolling this solution out throughout their hospitals and are finding it to be incredibly stable and has allowed the ICUs to have resilient performance of real-time clinical telemetry. This in conjunction with OSC for SCCM has enabled the customer to begin their rollout completely zero touch meaning we are providing a better solution to clinicians treating COVID patients without even having to touch a device.
The Requirements
To do this in a safe and secure manner, we needed the ability to provide credentials to an endpoint device and a framework to use said credentials to authenticate and then launch an endpoint specific URL in a browser that was configured to SSO to said URL. Additionally, it was imperative that the password could not be retrieved from the endpoint device.
This necessitated a few configuration items:
- Framework script
- Profile to execute script
- Utility to generate Kerberos keytab files [ktutil]
- Kerberos keytab
- Template key for URL
- If below IGEL FW 11.04.xxx, you can also use this with a Chrome custom partition with slight modification to the browser execution section in the framework script.
Having these items allowed a device to have the framework deployed, manage the identity to authenticate, and the location where they were authenticating to with simple assignment of a file and a template key. This provided the customer a secure solution to deploy a unique credential and unique URL to each device in a relatively scalable fashion. Comparatively, today they were doing this manually via a script and registry keys on existing Windows devices individually.
The Script
The actual script is a relatively simple BASH script that can be launched as a custom application running in user context. It isn’t perfect, but it gets the job done. The purpose of this script is to wrap around the entire workflow.
- Log all actions performed by the script
- Accept parameters to allow centralized management
- Find and identify user credentials (keytab)
- Initialize Kerberos
- Validate a Kerberos session properly initiated
- Launch Browser in a method it can SSO to site
- Repeat process on Kerberos session interval
There is no functionality for complete resiliency (like relaunching the browser on error, or validation of network, etc). That was beyond the scope of this initial solution. There are certainly improvements that can be made in that arena and feedback is always welcome. The idea behind this is that simply disabling the IGEL toolbar, executing this script, and providing the pre-reqs for the script can allow a tightly controlled kiosk experience that can be completely centrally deployed and managed. Troubleshooting and remediation for this solution is to simply reboot the device should it not appear to function.
#!/bin/bash #Kerberos Auto Login #Version 2.0 #6/20/2020 #Written by Wes Dobry ([email protected]) #PREREQS: #Keytab files need to be deployed to the $KEYTABDIR directory. #They need to be named in the following format: #[email protected] # #For instance, if my user was 'wes' and my kerberos realm (AD directory) was 'dobry.com' the keytab would need to be named #[email protected] # #The file must be named in all capitals except keytab or Kerberos will reject principal identity # #Requires 11.04.200 or higher to use embedded Chromium browser. ### # Usage: /wfs/kersautologin.sh 'authwhitelisteddomain.tld' 'domaintoautolaunch.domain.tld' ### #Setting up logger and dialog actions ACTION="KerberosAutoLogin" LOGGER="logger -it $ACTION" ERRORMSG="zenity --display=:0 --error --text $ERRORTEXT" #Directory containing keytab file KEYTABDIR="/wfs/keytab" #Browser Automation BROWSERCTRL=1 #Comment these two lines if you'd prefer to use arguments to the scripts. #Using arguments allows the use of template keys to provide the site information. #WHITELISTDOMAINS="*.lab.wesdobry.com" #STARTPAGE="http://micserver.lab.wesdobry.com:3000" #Uncomment the two lines below if you wish to use arguments to the script. #ie, /wfs/kerbsautologin.sh "*.yourintranetdomain.tld" "https://yoursite.tld" WHITELISTDOMAINS=$1 STARTPAGE=$2 #Comment out this if statement if you wish to use static entries instead of parameters. if [ $# -eq 0 ] then ERRORTEXT="Script needs arguments. Without arguments, you'll need to specify static entries in WHITELISTDOMAINS and STARTPAGE" echo $ERRORTEXT | $LOGGER $ERRORMSG exit 1 fi #find keytab echo "finding keytab" | $LOGGER KEYTABFILE=$(find $KEYTABDIR -type f -name "*.keytab") KEYTABNUM=$(echo $KEYTABFILE | wc -l) echo "Number of keytabs found = $KEYTABNUM" | $LOGGER echo "Keytabs found: $KEYTABFILE" | $LOGGER if [ $KEYTABNUM -eq 1 ] then echo "Only 1 keytab found. Continuing." | $LOGGER else if [ $KEYTABNUM -gt 1 ] then ERRORTEXT="More than 1 keytab found. Aborting." echo $ERRORTEXT | $LOGGER $ERRORMSG exit 1 fi if [ $KEYTABNUM -eq 0 ] then ERRORTEXT="No keytab found. Aborting." echo $ERRORTEXT | $LOGGER $ERRORMSG exit 1 fi exit 1 fi #Parsing identity from keytab echo "Parsing identity from keytab" | $LOGGER IDENTITY=$(basename $KEYTABFILE .keytab) echo "Identity found: $IDENTITY" | $LOGGER #start loop to repeat kinit process every 10 hours while : do #look for expired and if so, destroy echo "Checking for expired sessions" | $LOGGER KLISTOUT=$(klist) KLISTNUM=$(echo $KLISTOUT | grep -i expired | wc -l) if [ $KLISTNUM -gt 0 ] then ERRORTEXT="klist shows expired sessions. Destroying." echo $ERRORTEXT | $LOGGER echo $KLISTOUT | $LOGGER kdestroy else ERRORTEXT="klist shows no expired sessions. Continuing." echo $ERRORTEXT | $LOGGER echo $KLISTOUT | $LOGGER fi #initialize keytab echo "Initializing Keytab with identity $IDENTITY" | $LOGGER KINITRESULT=$(kinit -k -t $KEYTABFILE $IDENTITY) INITRESULT=$? if [ $INITRESULT -eq 0 ] then ERRORTEXT="kinit succeeded" echo $ERRORTEXT | $LOGGER else ERRORTEXT="kinit failed" echo $KINITRESULT | $LOGGER echo $ERRORTEXT | $LOGGER $ERRORMSG exit 1 fi #Verify kinit worked KLISTOUT=$(klist) KLISTNUM=$(echo $KLISTOUT | grep -i $IDENTITY | wc -l) if [ $KLISTNUM -ge 1 ] then ERRORTEXT="klist shows confirmed success" echo $ERRORTEXT | $LOGGER echo $KLISTOUT | $LOGGER else ERRORTEXT="May have been an error with kinit" echo $ERRORTEXT | $LOGGER echo $KLISTOUT | $LOGGER exit 1 fi #launch browser with parameters for SSO if [ $BROWSERCTRL -eq 1 ] then echo "Browser control requested in script. Starting browser with following parameters:" | $LOGGER echo "auth-server-whitelist=$WHITELISTDOMAINS" | $LOGGER echo "auth-negotiate-whitelist=$WHITELISTDOMAINS" | $LOGGER echo "start-page=$STARTPAGE" | $LOGGER /usr/bin/chromium-browser --incognito --disk-cache-size=100000000 --start-maximized --auth-server-whitelist=$WHITELISTDOMAINS --auth-negotiate-whitelist=$WHITELISTDOMAINS --kiosk $STARTPAGE & #/usr/bin/chromium-browser --incognito --disk-cache-size=100000000 --start-maximized --auth-server-whitelist=$WHITELISTDOMAINS --auth-negotiate-whitelist=$WHITELISTDOMAINS $STARTPAGE & else echo "Browser control not requested. Not launching browser." | $LOGGER fi #wait for 10 hours and reinitialize keytab echo "Waiting for 10 hours to reinitialize kerberos" | $LOGGER sleep 10h echo "Reinitializing Kerberos" | $LOGGER if [ $BROWSERCTRL -eq 1 ] then echo "Browser control requested in script. Killing browser to begin reinitialization" | $LOGGER killall chromium-browser echo "Browsers killed" | $LOGGER else echo "Browser control not requested. Doing nothing." | $LOGGER fi done
The Profile
The profile to configure this is very simple. It is a single custom application to launch the deployed framework script with some parameters.
The command to execute is:
/bin/bash /wfs/kerbsautologin.sh “*.yourSSOdomain.tld” ${KerberosURL}
For example, if I wanted to use this with a site like “intranet.lab.wesdobry.com” the command would look like:
/bin/bash /wfs/kerbsautologin.sh “*.lab.wesdobry.com” ${KerberosURL}
Here’s what my configuration looks like:
And a template key named “KerberosURL” would be configured with the requisite URL.
The Credential
The login information for Kerberos can be stored in a keytab file. This is a cryptographic file containing keys that can be leveraged to initiate a Kerberos session. This would be similar to storing auto-login information in the Windows registry with an LM hash, but more secure as it cannot be decrypted. The only information that can be gained from a keytab file is the Kerberos principal and the ability to initiate a Kerberos session. So, while this is a way to gain authentication information, they can be generated and stored securely to reduce exposure risk.
To generate the keytab, a utility named ktutil can be employed (https://web.mit.edu/kerberos/krb5-1.12/doc/admin/admin_commands/ktutil.html). It is a multiplatform tool. I downloaded the ubuntu apt package and isolated the binary and deploy it as a file to an admin workstation for purposes of generation of the keytab file, but there’s nothing restricting the use of a Windows workstation to do the same.
When you have ktutil deployed to a linux workstation that has ability to reach your Kerberos KDC, you can generate a keytab as follows:
./ktutil
Then within the ktutil session run the following commands:
addent -password -p [email protected] -k 1 -e RC4-HMAC password write_kt USERNAME.keytab
Please note that the principal and output file name need to be uppercase or you will run into Kerberos auth errors.
To simplify this, I have written a wrapper script to generate keytab files with parameters.
user=$1 password=$2 printf "%b" "addent -password -p $user -k 1 -e RC4-HMAC\n$password\nwrite_kt $user.keytab" | ktutil printf "%b" "read_kt $user.keytab\nlist" | ktutil
Figure 5 – generateKeytab.sh script
With this, you can run the following command and it’ll output the requisite keytab file.
./generateKeytab.sh [email protected] P@55w0rd
Take the generated keytab and deploy it to your endpoint as a file. In the script, it requires it to be in /wfs/keytab but this location can be changed to a location of your choosing.
The Bundle
Now with all the bits generated, they can be applied to a device or folder in your UMS. You should have the following applied:
- Script file to /wfs/kerbsautologin.sh
- Keytab (in uppercase) to /wfs/keytab
- Template Key value for your URL to SSO to
- Profile to launch kerbsautologin.sh with parameters for auth domain and URL template key
In my lab, I can apply everything at the folder level as I am sharing the same credential and URL across all test devices. In my customer’s environment, the keytab and URL are applied at the individual device and are managed via their end-user support team through the use of the Web UMS. This allows unique credentials and URLs on a device per device basis throughout the organization and enabled rapid change through delegated administration.
The Download
All scripts, profiles, and tools referenced in this post: