One of the most requested features for the Casper Suite’s FileVault 2 implementation is the ability to automatically re-issue individual recovery keys after a single use. The idea here is that once the key has been used it can be considered compromised — it may have been sent to a user in an email from IT or it may have been written down on a notepad somewhere. Bearing this in mind it would be far more secure if after a single use of the key a new key could be automatically re-issued thereby rendering the old key useless.
It turns out that this is actually quite easy. There is an option in the fdesetup binary that will tell you if a recovery key has been used to unlock the drive. From the fdesetup man page:
usingrecoverykey [-verbose] Returns the string "true" if FileVault is currently unlocked using the personal recovery key.
When the recovery key is used at the FileVault 2 pre-boot login screen, the user will be prompted to reset their password. Once this is complete the machine will log in as normal. Running the command fdesetup usingrecoverykey will return true at this point until either the machine reboots or the recovery key has been re-issued.
For those unfamiliar the end user experience looks like this. At the FileVault 2 pre-boot login screen there’s a ? in the password field. When clicked the user is presented with an option to reset their password using the recovery key.
At this point, the user is now logged in and the password has been reset so running:
will return true.
The idea I had was to run a script at login that would check to see if the recovery key had been used and if so request a new recovery key from the JSS. One of the issues I quickly ran into is that on a laptop connected via WiFi the script runs before the network is connected and therefore the policy to re-issue the recovery key fails. I got around this by building in a loop that checks for a connection to the JSS before calling the policy that re-issues the recovery key.
jamf checkJSSConnection -retry 0 until [ $? = 0 ] do sleep 5 jamf checkJSSConnection -retry 0 done
This will loop indefinitely until the JSS can be reached so even if the machine is unlocked with the recovery key and then kept offline for hours it will still request a new key as soon as it makes contact with the JSS.
The policy to re-issue the recovery key is called via a custom trigger (I’m using ‘issueNewRecoveryKey’ in my script). I’ve set the execution frequency to ongoing, and scoped the policy to all machines. In the Disk Encryption payload, I’ve set the options to issue a new individual recovery key.
The final step was to get the script to run at each login. I mentioned before that connectivity to the JSS could be delayed at login, as a result I found that running the script via a JSS login policy was not reliable when connected via WiFi. Instead, I placed the script locally on the machine, and created a launch agent to run the script at login. This proved to work far more reliably over WiFi.
There are a few caveats involved with this workflow:
- As the script and launch agent live on the machine, a user with admin credentials could easily bypass or remove them.
- Using the recovery key to unlock the disk while in target disk mode would not trigger this script.
- If the drive is unlocked with the recovery key, the password is reset, and the computer is rebooted before contacting the JSS, the script will not request a new key from the JSS.
For these reasons, I recommend using this workflow in tandem with a daily or weekly automatic rotation of recovery keys for added security.
It’s also worth noting that the usingrecoverykey option isn’t present in fdesetup prior to OS X 10.9 Mavericks.
My script is below. Feel free to modify it and use it in your environment.