Authenticated Web Kiosks with IGEL OS and Kerberos

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.

Figure 1 – Telemetry GUI Screenshot

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.

  1. Log all actions performed by the script
  2. Accept parameters to allow centralized management
  3. Find and identify user credentials (keytab)
  4. Initialize Kerberos
  5. Validate a Kerberos session properly initiated
  6. Launch Browser in a method it can SSO to site
  7. 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:

Figure 3 – Kerberos Auto Login Profile Example

And a template key named “KerberosURL” would be configured with the requisite URL.

Figure 4 – Template Key Configuration

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
Figure 6 – Assigned objects for full solution

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:

The Demo