Setting An Apple Silicon Recovery Lock Password Through the Jamf API

In Big Sur 11.5, Apple introduced the ability to set a recovery lock password on Apple Silicon computers. This was a very welcome announcement, since many of us have been mourning the loss of the EFI firmware password that was so effective on Intel Macs.

The firmware password was an important security feature, especially in environments like schools. It prevented students from booting to Recovery Mode, where they would be able to erase the hard drive, run terminal commands, reset passwords, use Safari unfiltered, and do all kinds of other nefarious acts.

Apple’s answer to these security concerns is simply to enable FileVault. This is flawed for a couple reasons:

  1. FileVault removes the ability to control lab computers through ARD. After a restart, there is no way to remotely take action on these computers until the disk is unlocked by someone physically sitting at the computer and typing in a password. This is a huge pain for things like updates and remotely installing software.
  2. Even when FileVault is enabled, students can erase the computer from the FileVault unlock screen. Try it for yourself – no password is needed and you can erase the disk.

When the Recovery Lock MDM command was announced, we cheered. And then waited. And waited some more. 11.5 came out in July of 2021. Jamf announced support for Recovery Lock in September of 2021 in Jamf Pro 10.32…but only during PreStage Enrollment. On top of that, there were multiple bugs reported right off the bat. Even if it weren’t buggy, we had already enrolled all of our computers during the summer and had no plans to wipe and re-enroll them all. We were content to wait and see if Jamf included the MDM command in an upcoming release.

As I write this, it’s January of 2022 and the MDM command still isn’t available. It’s become an issue here, as we found evidence that students had figured out that they could boot to Recovery Mode on lab computers. I had to put a stop to it.

I decided to take matters into my own hands and wrote up this script. It takes the contents of an advanced search, loops through the computers-preview endpoint on the Jamf Pro API to get management IDs for all computers in the search, and uses the /api/preview/mdm/commands endpoint to send the recovery lock command. Big thanks to Florian Poncelin for the comments on this feature request that led me down the right path!

Some caveats:

  • This can only be run on an advanced search that contains 2000 or fewer computers. This is due to the pagination in the Jamf Pro API. I started to play with looping through the pages, but it’s honestly hard for me to test since we don’t have over 2000 computers and I needed to get this working as quickly as possible. If you have more than 2000, you can write the pagination part yourself, or break your computers up into multiple advanced searches with fewer than 2000 computers each.
  • jq is required to run the script. You can install jq through homebrew, or one of the other methods on their website. I dislike external dependencies as much as the next person, but there aren’t many good options for dealing with JSON that don’t require installing an extra tool. Some awesome Mac Admins have figured out how to use Javascript for this, but I don’t know Javascript well enough (yet) to accomplish such a thing.
  • You will be setting the same Recovery Lock password on all computers with this method. If you set the password through the PreStage Enrollment option, you have the ability to randomize the password. That is not possible here. It will also be stored in plaintext in Jamf Pro, viewable by any user that has the View Recovery Lock permission set in Jamf Pro Server Actions.

Before running this, you need to create an advanced computer search that has all of the computers you want to have a Recovery Lock password. This can be lab computers, Apple Silicon computers, or whatever other criteria and display options you want – all we are using the search for is getting the ID numbers of the computers. Just remember that if there are more than 2000 computers in the search, the command will not go through after the first 2000.

You will need to get the ID number for the advanced search itself. The easiest way to get this is to click on the advanced search in Jamf Pro and note the number that appears in the address bar after ?id= This is the number you will input in the script, either as the value for searchNumber or when you are prompted for it if you are running the script interactively.

Example – this search ID number is 172.

The computers that get the command will not get a prompt or see any indication that the password has been set. If a computer is offline when it is sent, the SetRecoveryLock command will be in a pending state until it is online.

#!/bin/zsh

#authentication - you can fill in these lines and add your information if you don't want to be prompted interactively when the script runs
#the jamfURL should be exactly what you type into the address bar to access Jamf (no slash at the end)
jamfURL=
jamfUsername=
jamfPassword=

if [ -z $jamfURL ]; then
	echo "Please enter the Jamf Pro URL (with no slash at the end):"
	read -r jamfURL
fi 

if [ -z $jamfUsername ]; then
	echo "Please enter your Jamf Pro username:"
	read -r jamfUsername
fi 

if [ -z $jamfPassword ]; then 
	echo "Please enter the Jamf Pro password for account: $jamfUsername:"
	read -r -s jamfPassword
fi

#encoding credentials so they aren't sent in plaintext
encodedCreds=$(printf "$jamfUsername:$jamfPassword" | iconv -t ISO-8859-1 | base64 -i -)

#using encoded credentials to get bearer token
token=$(curl -s "${jamfURL}/api/v1/auth/token" -H "Authorization: Basic $encodedCreds" -X POST | jq -r '.token')

#setting field separator to newline
IFS=$'\n'

#search number - you can fill in the search number here if you don't want to be prompted
#this search should have less than 2000 computers in it
searchNumber=
if [ -z $searchNumber ]; then
	echo "Please enter the number of the advanced computer search you want to send the command to:"
	read -r searchNumber
fi 

#recovery password - you can fill in the recovery password here if you don't want to be prompted
recoveryPassword=
if [ -z $recoveryPassword ]; then
	echo "Please enter the recovery password you would like to set on these computers:"
	read -r recoveryPassword
	echo "Password will be set to $recoveryPassword"
fi

#looping through computers in advanced search
computers=($(curl -s "${jamfURL}/JSSResource/advancedcomputersearches/id/$searchNumber" -H "Accept: application/json" -H "Authorization: Bearer ${token}" -X GET | jq ".advanced_computer_search.computers[].id" ))
	for computerID in "${computers[@]}"; do
		#get the Management ID for computers in the search
		echo "Processing computer number $computerID"
		managementID=$(curl -s "${jamfURL}/api/preview/computers?page-size=2000" -H "Accept: application/json" -H "Authorization: Bearer ${token}" | jq -r '.results[] | select (.id=='\"$computerID\"') | .managementId' )
		#send the recovery lock command
		curl -s "${jamfURL}/api/preview/mdm/commands" -H "Content-Type: application/json" -H "Authorization: Bearer ${token}" -X POST -d "{\"clientData\":[{\"managementId\":\""$managementID"\",\"clientType\":\"COMPUTER\"}],\"commandData\":{\"commandType\": \"SET_RECOVERY_LOCK\",\"newPassword\":\""$recoveryPassword"\"}}"	1 > /dev/null
		echo "Recovery Lock command sent to computer number $computerID."
	done

#cleaning up
curl -s -k "${jamfURL}/api/v1/auth/invalidate-token" -H "Authorization: Bearer ${token}" -X POST
unset IFS

echo "Complete. All computers in the advanced search have been sent the Recovery Lock command."

After running the script, you will be able to tell that it has succeeded by checking the inventory of a computer that completed the command. The security settings will show that there is a recovery password. You can click on the Show Password button to see the password in plaintext. The computer will most likely show Recovery Lock: Not Enabled right after the command is sent. This is okay. At the computer’s next recon, it will update with the correct status.

Clicking on “Show Password” will show you what the password has been set to.

That’s it. Booting to recovery will show a login prompt with no options available.

Just like in the old EFI password days!

Leave a Comment

Your email address will not be published. Required fields are marked *