Automatically fixing MDM certificate enrollment with Casper 9.x
UPDATE – 9-22-2014: JAMF brought back the jamf mdm command in Casper 9.4, so it’s possible to use the workflow described in this post in Casper 9.4 and later.
A while back, I wrote a post on fixing Casper Mac MDM enrollment. This post covered my experiences with Casper 8.7.x and provided a method to automatically fix any problems with the MDM certificate. Unfortunately, the method that works in 8.7.x does not work in 9.x because the command that I use to do the MDM enrollment in Casper 8.x is jamf mdm. As part of the change from Casper 8.x to 9.x, the function performed by the jamf mdm command is now handled by the jamf manage command in Casper 9.x. The jamf mdm command itself does not exist in Casper 9.x
To duplicate the general process which I’m using in Casper 8.x, I needed to run the following commands:
/usr/sbin/jamf removeMdmProfile -verbose /usr/sbin/jamf manage -verbose /usr/sbin/jamf recon
The issue I ran into is that jamf manage waits until all policies are finished running, which meant that the MDM fix is running after the jamf recon command completes its inventory update and sends it on to the Casper server. The consequence is that the Casper server would never be informed that the machine had actually been fixed, which potentially cues an infinite loop of fixing a problem which is already fixed.
So I had two issues:
1. I wanted to fix my problem with a Casper smart group that would contain only affected machines and an associated Casper policy that would fix the machines in the smart group. This would allow the problem to be automatically detected and then fixed without the need for human intervention.
2. I needed to make reasonably sure all policies were finished running before trying to run the jamf manage command. Otherwise, running jamf manage would result in the recon running before the MDM certificate gets fixed.
On top of that, I preferred that jamf manage only be run once rather than building a process that potentially ran it a large number of times.
To sum up:
A) I wanted to fix the problem automatically with a Casper policy.
B) I couldn’t directly fix this with a Casper policy. Running the commands above using a policy would mean that jamf manage and jamf recon would not run in the order I wanted them to, with the undesired “infinite loop” consequences described above.
Shea Craig gave me the idea of using a LaunchDaemon and script to run the commands I needed, but I still needed a reliable way of determining if Casper policies were running. Shea’s approach relies on killing the jamf process as needed, but that ran the risk of interrupting any active policies or other tasks that were running.
After mulling over the problem for a while, I thought of another way to determine if a policy was running. /var/log/jamf.log is updated when Casper policies or check-ins run on an individual Mac, so if the log hasn’t been updated in a while, it is very unlikely that a policy is running.
Using this idea, I wrote a script and an associated LaunchDaemon to perform the following tasks:
1. Verify that the Mac can contact the Casper server.
2. Verify that /var/log/jamf.log has not been written to in the past five minutes.
3. If /var/log/jamf.log has not been written to in the past five minutes, fix the MDM certificate and communicate that it is fixed to the Casper server.
4. Delete itself and its associated launchdaemon.
For the details, see below the jump.
The LaunchDaemon assumes the script above has been installed as /var/root/fixcaspermdm.sh. The LaunchDaemon runs the script when the LaunchDaemon is loaded and then attempts to run it once every 10 minutes thereafter.
I still had the issue of deploying this solution. I decided to fix this with a payload-free package, which performs the following tasks
1. Determines if the Mac is running 10.7.x or later.
2. If any previous instances of a specified LaunchDaemon and script exist, unload the LaunchDaemon and remove the LaunchDaemon and script.
3. Create the LaunchDaemon described above by using cat input redirection to write the XML contained below to a new file.
4. Create the script by using cat input redirection to write the script described above to a new file.
5. Once the LaunchDaemon file has been created, fix the permissions so that the file is owned by root:wheel and set to not be executable.
6. After the permissions have been updated, move the LaunchDaemon into place in /Library/LaunchDaemons.
7. Once the script file has been created, fix the permissions so that the file is owned by root:wheel and set to be executable.
8. After the permissions have been updated, move the script into the place that it will be executed from.
9. After the LaunchDaemon and script are in place with proper permissions, load the LaunchDaemon to begin the script’s execution.
Payload-Free Package Script:
I then created a payload-free package using the script above and Payload-Free Package Creator.
Now I had a solution that would fix the MDM certificate, but I still needed to be able to identify machines with the MDM certificate problem and then deploy the solution with Casper 9.x. Fortunately, here I could use the same strategy on Casper 9.x that I had on Casper 8.x.
To help identify machines with this problem, JAMF provides three extension attributes with your Casper JSS server to help you identify machines with either problematic SSL certificates or missing MDM certificates.
JSS Certificate Validation
Verify Certificate Based Communication
Verify MDM Enrollment
All can be installed from the JAMF Software category of your Casper server’s Computer Extension Attribute Templates.
From there, you can set up a Smart Group to look for machines that fit the following criteria:
JSS Certificate Validation – Success
Verify Certificate Based Communication – Enabled
Verify MDM Enrollment – Not Enrolled
It should also currently be scoped to look for Macs running 10.7.x or higher, as earlier OSs won’t be enrolled in MDM.
Here’s how the smart group I set up looks in Casper 9.3.x:
From there, set up a policy that is scoped to run on members of that smart group. The policy I set up will install the payload-free package, which in turn will create and load the LaunchDaemon and script to fix the problem.
Once the script has fixed the MDM certificate issue, the script will trigger a new inventory to run and send the results to the Casper server. The updated inventory should then allow the JSS to detect that the MDM certificate has been installed and take the machine out of the smart group.
Here’s how the policy I set up looks in Casper 9.3.x: