Why you should use FileVault personal recovery keys instead of institutional recovery keys

In my previous blog posts on FileVault, I talked about or showed how to use an institutional recovery key for FileVault encryption:
Enabling FileVault Encryption for Client Macs
Setting up deferred FileVault encryption
Using a FileVault institutional recovery key to unlock an encrypted disk

But in exploring FileVault further, I've found it's much better to use personal recovery keys instead of a single institutional recovery key, and it's not for the reason you might think.

IRK not necessarily less secure than PRK

Yes, from a security standpoint, you could make the case that an institutional recovery key creates a single breach point (someone obtains that one recovery key and thus can decrypt all your institution's machines), but I don't think this makes personal recovery keys more secure necessarily. First of all, the personal recovery key itself can unlock a machine, but the institutional recovery key is used in combination with a password to unlock the keychain. Secondly, most likely you're storing your personal recovery keys all in one place—it may be a secure place, but it's also a single breach point. If you somehow access that one storage location (database, spreadsheet, whatever you're using to store the personal recovery keys), you have access to all the recovery keys for all the machines.

I suppose you could scatter the personal recovery keys in multiple storage locations. There is always an artistic (not scientific) balance between security and convenience, so that's up to you how you decide to store things. The point, though, is that an IRK is not necessarily less secure than a PRK.

IRK is less useful than a PRK, though

As I was rolling out encryption to our fleet using an institutional recovery key, I started to realize through testing (fortunately not through an actual emergency) how limited in functionality the institutional recovery key is compared to the personal recovery key.

First of all, unless you are physically in front of the machine or using ARD to remote into a virtual session, you cannot enable another FileVault user without storing the password for it in plain text. If you try to do so via SSH and the command-line, you'll be prompted for the password of an FV-enabled user or for the personal recovery key, so having the IRK doesn't help there.

That's not really the worst part. The worst part is that, as far as I can tell (based on Google searches, asking other Mac admins, and just trial and error), there is no way to reset a forgotten user password with just the institutional recovery key. You can unlock the encrypted volume and save the data, but you can't just say "Reset this user's password." You can, as a horribly long workaround, decrypt the drive, log in as another admin user, reset the other user's forgotten password, wait for the decryption to finish completely, and then re-encrypt. That can take a really long time.

But if you just use personal recovery keys, you can have the user try to log in three times, and she'll be prompted to enter the recovery key to reset the forgotten password, and then be prompted to enter a new password.

Wesley Whetstone has created a neat little pkg that can generate/regenerate personal recovery keys: fde-rekey.

Once you've switched that over, you can also remove the institutional recovery key (yes, it's possible to have both an IRK and a PRK). If you're using Munki, I wrote a nopkg that will remove the IRK after fde-rekey is installed.

Automating an AutoPkg Munki import when vendors don’t package installers properly

You may have, when using (or creating) a .munki AutoPkg recipe, come across a situation in which you run it:

autopkg run -v NAMEOFITEM.munki
and then get something back like this:
Item NAMEOFITEM already exists in the munki repo as OLDNAMEOFITEM.
even though you're sure the item is newer than the one in the Munki repo.

That has to do with the find_matching_item_in_repo() function the MunkiImporter processor uses to determine whether the item exists already or not.

It compares a number of things between the to-be-imported item and what's already in the Munki repo—installer item hash, installs, receipts, files and paths, etc. If any of those matches up, MunkiImporter considers it a match.

So, for example, if you have BADLYPACKAGEDBYVENDOR 3.7.3, which is an update for BADLYPACKAGEDBYVENDOR 3.7.2, but the receipts for both are just 1 (yes, 1 and not 3.7.2 or 3.7.3), the MunkiImporter processor will see the two as the same and not do "another" import of the same item. Likewise, if the version in the app bundle is 3.7 and not 3.7.2 or 3.7.3, the MunkiImporter processor will see them as the same. I've even run into situations in which a vendor artificially ups the number but the "new" package or .app bundle is exactly the same. In that case, the installer hash will be the same, and the MunkiImporter processor will see them as the same.

So what do you, apart from complain to the vendor and pray it fixes the problem?

There may not be anything you can do apart from force an import. You may find a convoluted workaround, though. For LockDown Browser, I had to create an installs array based on the executable and also essentially override the useless receipts array. You might have to do something similar, depending on how bad the vendor package is.

Using an Outset boot-every script to add default applications via Munki

In Bash script to add optional installs for Munki, I introduced a script that uses PlistBuddy to add optional install items to the client machine's SelfServeManifest.

I thought at first I could use that as a boot-once script for Outset, but it seemed the script ran too early (actual first boot) and then didn't actually write the values it should.

As a workaround, I've put the script in as an Outset boot-every with a check to see if one of the optional items is already in the Munki install log. Here's an example:


# See if this has ever run before... have to check the log, because Outset will delete the file once run. We don't want this to re-run if we update the pkg version
alreadyRun=$(cat /Library/Managed\ Installs/Logs/Install.log | grep "Firefox")

if [ -z "$alreadyRun" ]; then

# Self-serve manifest location
manifestLocation='/Library/Managed Installs/manifests/SelfServeManifest'

# PlistBuddy full path

# Add in "optional" default software

# Check to see if the file exists. If it doesn't, you may have to create it with an empty array; otherwise,
if [ ! -f "$manifestLocation" ]; then
sudo "$plistBuddy" -c "Add :managed_installs array" "$manifestLocation"

for packageName in "${optionalDefaults[@]}"
# Check it's not already in there
alreadyExists=$("$plistBuddy" -c "Print: managed_installs" "$manifestLocation" | grep "$packageName")

# Single quote expansion of variables gets messy in bash, so we're going to pre-double-quote the single-quotes on the package name

if [ -z "$alreadyExists" ]; then
sudo "$plistBuddy" -c "Add :managed_installs: string $alteredPackageName" "$manifestLocation"

So this basically checks for Firefox. If Firefox (one of the default optional installs) is in the install log, it won't run again.

When an AutoPkg recipe fails to import a .dmg

If you ever have an AutoPkg recipe that seems to be working fine for weeks or even months and then suddenly fails with a message like this one:

Error in local.munki.FileZilla: Processor: MunkiImporter: Error: creating pkginfo for
/Users/USERNAME/Library/AutoPkg/Cache/local.munki.FileZilla/FileZilla.dmg failed: Could not mount
(doesn't have to be FileZilla—could be anything), you may not see the .dmg is mounted in Disk Utility (or even diskutil list), but you can check to see if it's a phantom mount by seeing if it shows up in the output of
hdiutil info
If it does show up there, then run
hdiutil detach /dev/diskFILLINLOCATION
and then re-run the recipe. Should be fine after that.

Acknowledgements: Thanks to Eric Holtam for the tip—just documenting it here for anyone else who may benefit from it.

Using DVD Flick to create DVDs from video files

DVD Flick is an open source Windows program that allows you to burn various video file types to DVD (as an actual DVD, not as a data file).

It's fairly simple to use, but there are a couple of weird nuances:

  1. By default, it doesn't actually burn to disc when you create the DVD. It creates a DVD-ready set of files in a folder on your computer. In order to actually make the DVD, you have to change the settings in your project by going to Project Settings > Burning > Burn project to disc.
  2. Also by default, there is a weird audio delay (similar to bad dubbing on Bruce Lee movies from the 70s). In order to get rid of that delay, you have to go to Edit title... > Audio tracks > Edit > Ignore audio delay for this track.

Hide optional installs in Managed Software Center using JavaScript

Munki 3 brings in something called "Featured items" to Managed Software Center. You can read some munki-dev mailing list discussion about the feature before its implementation.

The way it's implemented, you add in this key

to the pkginfo of the optional installs item you want to have show up in the Software tab of Managed Software Center.

So, previously, the idea was that all optional installs would show up there. With Munki 3, only optional installs marked as "featured" will appear on the main page, though you can still find all optional items through a search or by browsing categories.

If you would like to have the hiding of optional install items per client (and not per item via the pkginfo key), you can use this JavaScript hack I threw together.

Just modify the array of items to omit, and then plop it into the footer_template.html of your client customization.

The script checks that your user is on the All items (Munki 2) or Featured items (Munki 3) page. If your user is on that page, it will hide all the items to omit. Otherwise, it will show all items (so items aren't disappearing from the search results or from category browsing).

Acknowledgements: Hat tip to Erik Gomez for the idea.

Apple TV “the code is incorrect” error… when the code is correct!

We ran into a weird scenario where a user could not connect to Apple TV with a passcode. We tried all the usual troubleshooting stuff:

  • Does it work with another computer? Yes, it does.
  • Does it work with another user on the same computer? No, it doesn't.
  • Toggle Bluetooth? Makes no difference.
  • Reboot the AppleTV and the computer. No difference.
  • Double-check the key mapping is fine on the Mac itself. It is.
  • Try to connect to a different Apple TV. Same problem.
  • Is the time correct? Seems to be.
Ah, but that ended up being the problem (kudos to my colleague, Jerold, for finding this)—even though the time and date were technically "correct," we had to turn on location services and then set the time zone to be detected automatically in order for the Mac to connect to the Apple TV.

That's weird. It's weird because the time and date were definitely correct, and it's weird because other Macs do not have the time zone set to be detected automatically and are still able to connect to Apple TVs on campus.

But if you run into this issue where you're prompted for a passcode to connect to an Apple TV, and it keeps giving you the code is incorrect when you're absolutely sure you've typed the correct code, consider setting the time zone for automatic detection.

Script making Chrome the default browser on macOS

You would think it would be fairly simple to script changing the default browser to Chrome in macOS. It's not, as far as I can tell! I'd love to be corrected on this.

Script that changes Launch Services

I wrote up a script that changes the default browser silently, but it works well only the first time you run it.

If you run it again to switch to another browser, you may have to reboot for the change to take effect. Sometimes changing the default browser through the GUI and then running the script again will have it work again.

That means it's a bit messy. On the other hand, in terms of practical use, you're not likely to want to script changing the default browser multiple times on one machine—the whole point of scripting it is likely to just make an initial default the user can change later on her own should she choose to, and she can use the GUI to do that.

If you want to use this in conjunction with Outset but not have the settings change for existing users (only new ones), you can use this preinstall script to fake-run the login-once script for each existing user.

I think this is a great option (and not just because I worked hard on it), but I also outline below some other options.

cdef and defaultbrowser

cdef and defaultbrowser allow you to set the default browser. Unfortunately, as far as I can tell, all that does is pop up the regular GUI "set default browser" dialogue: Again, if someone knows of a silent option I don't know about, please leave a comment below, and I'll update this entry.

duti works great... but not for Chrome

In Using duti to script default applications for Macs, I detail the steps for using duti in general, which works great... in general. It just chokes on setting the default browser. If you try to use duti to set Chrome as the default browser:

com.google.chrome public.html all
com.google.chrome public.xhtml all
com.google.chrome http all
com.google.chrome https all
you will get the error:
failed to set com.google.chrome as handler for public.html (error -54)

Using Munki to rename computers based on manifest display name, user, or notes

There may be some Mac admins who don't really care that much about computer names. After all, especially if the computer isn't joined to the domain (many of our machines are not), what does it matter? It's the name that will show up in Sharing or in the Terminal.app few users use. If you do care, though, I created a Munki nopkg that looks at one of three places for a name to rename the computer name to—display_name, user, or notes.

I based this on the three custom fields that MunkiAdmin has editable for manifests.

To use it, just modify the display name, user, or notes field in the manifest you want to rename, tweak in the nopkg (via commenting/uncommenting) the installcheck_script and postinstall_script to use the field you want, and then add this nopkg as a managed_installs item to the manifest(s) you want to manage computer names for. This nopkg will change the LocalHostName, HostName, and ComputerName.

As written, this nopkg will automatically ignore AD-bound computers.

P.S. If you have a database or spreadsheet of some kind of what the computer names should be, you can also bulk-fill-in those fields. I have a simple (no subdirs on my manifests) sample script you can tweak.