Fixing MDM Communications With Apple Business Manager Migration

Introduced in macOS 26 Apple Business Manager (ABM) supports migrating devices from one MDM to another.  One unintended feature of this is the ability to use the migration to repair broken MDM communications, including mismatched APNs topics with expired MDM profiles. This saves IT from performing a device erase or going into recovery mode.

This guide will go over how to correctly set up Apple Business Manager and Jamf to repair MDM communications. At a high level we’ll be creating a 2nd Management Service in Apple Business Manager that links back to the same Jamf Pro Server. This will allow us to “migrate” devices from Jamf Pro to Jamf Pro which will force a reenrollment.

Interested in more MDM Communication fixes? Check our our JNUC Sessions Flawless MDM Communication and Flawless MDM Communications: Scripting Edition

Feedback has been sent to Apple to allow ABM to simply execute a fix.


Jamf – Download Jamf ADE Public Key

Login to Jamf Pro and navigate to Settings > Global > Automated Device Enrollment and download the Public Key at the top right

ABM – Create Device Management Service

Login to Apple Business Manager account and navigate to Preferences > Device Management Services and Click Add

Service Info: Company Jamf Fix

UNCHECK Allow this device management service to release devices.

Upload the public Key previously downloaded.

Click Save

Click Download Token

Jamf – Create ADE Enrollment

Login to Jamf Pro and navigate to Settings > Global > Automated Device Enrollment and click New

Display Name: Company Apple Business Manager Fix

Upload the token from above.

Supervision identity for user with Apple Configurator: None

Jamf – Clone Computer PreStage

Login to Jamf Pro and Navigate to Computers > PreStage Enrollment

Click on the primary PreStage enrollment for computers

Click Clone at the bottom

Add “fix” to the end of the display name

Change Automated Device Enrollment Instance to ABM fix

Check Automatically assign new devices.

Click Save

Jamf – Clone Device PreStage

Login to Jamf Pro and Navigate to Devices > PreStage Enrollment

Click on the primary PreStage enrollment for devices

Click Clone at the bottom

Add “fix” to the end of the display name

Change Automated Device Enrollment Instance to Company ABM fix

Check Automatically assign new devices.

Click Save

Repairing a device

Jamf – Identify Device serial and eligibility

When you’ve identified a device that needs to be repaired, go into Jamf and get its serial number. Also verify that it’s running at least macOS 26 Tahoe.

ABM – Assign Device

Login to the ABM and click Devices.

Search for the Serial number

  • If the serial number isn’t here then the device isn’t in Apple Business Manager and isn’t eligible for repair. But it can be automatically repaired using Mann’s APNs fix workflow.

Click the … in the upper right corner of the record and then Assign Device Management

Select the Company Jamf Fix instance and set a deadline, usually 1 week away at 8:30am local time is best. 

Once you click continue the device will be forced to move through the process.

Employee Experience

macOS user experience

As the deadline approaches, users will get notifications informing them that management of their device needs to be updated by a specific date. These appear every 24 hours then hourly leading up to the deadline.

When the user clicks Start Enrollment, they will get a full screen pop-up where they can click Enroll. If the user clicks this before the deadline, they will have the option to defer with Not now. 

Once Enroll is clicked profiles start installing, after a few moments when everything is downloaded and Enrollment complete messages appears

Once quit is clicked no restart is necessary.

iOS user experience

The user will receive a prompt that enrollment is required.

Following this prompt will bring the user to the Settings app:

Selecting Start Enrollment will show a subsequent prompt notifying the user that a restart is required:

After selecting Restart, the device will promptly reboot and complete the enrollment in the new MDM service. The migration is now finished.

If the user elects to exit this flow at any point by selecting Not Now, they will be able to re-initiate it through Settings by tapping the Enrollment Required notice.

Details button not working in Jamf Pro policy logs

Starting with the 11.13 update Jamf Pro administrators have reported that the details button in policy logs isn’t working as intended. Instead of showing the details of the policy clicking this button no longer does anything. This can make troubleshooting policy errors difficult.


Fortunately after some discussions on Mac Admins Slack https://www.macadmins.org it’s been identified that clearing all the browser cache will fix this issue. As a bonus Jamf has now fixed PI120308, introduced in November 2024 that resulted in the policy logs no longer having a horizontal scroll bar!

Google Chrome Fix

For Google Chrome simply choose Chrome from the Menu Bar, then “Delete Browsing Data…”

Select only “Cached images and files” then click Delete data.

Refresh the Jamf Pro console and the Details button should now work!

Major macOS deferrals may rollback security fixes

Apple provides the ability to defer major macOS upgrades to prevent early adoption of major OS versions on managed devices.  Having a major deferral in place that’s longer than an existing minor deferral may leave computers with an immediately pending macOS update after a macOS Upgrade, which could cause computers to rollback already applied security fixes. Computers will be left vulnerable to previously patched flaws until the available update is applied.

This article is written based on the following configuration:

  • Today’s date: December 16th, 2024.
  • Upgrade: Major version change, example: macOS 14 -> macOS 15.
  • Update: Minor version change, example macOS 15.0.1 -> macOS 15.1

How the rollback happens:

macOS 15 was released 91 days ago on September 16, 2024, so a Major deferral of 90 days has now expired. Computers running macOS 14 will now see the macOS 15.0 available update in System Settings. Note I say macOS 15.0, not macOS 15.0.1 or macOS 15.1.1. This is because the 90 day Major deferral logic fully defers all major versions for 90 days of their release. macOS 15.0.1 was released 74 days ago on Thursday, October 3, 2024 which is less than 90 days ago, so it remains deferred. 

Since we have a 14 day minor deferral in place most of our computers should be on macOS 14.7.1 with Safari 18.1.1 update applied. Safari 18.1.1 Fixes CVE-2024-44308 and CVE-2024-44309, both of which are considered under active exploit for Intel systems. These vulnerabilities were also fixed in macOS 15.1.1, but our computers will be upgrading to macOS 15.0… So computers will go from a patched state to a vulnerable state on upgrade.  After the upgrade the computer will need to then perform a minor update to macOS 15.1.1, which is allowed under the minor deferral configuration in place.

How to fix this:

Organizations should immediately reduce their major deferral to match their minor deferral. Systems will then upgrade to the version of macOS 15 with a similar patch level of their existing macOS 13 and macOS 14 systems. This needs to be done every release cycle.

Long term fix:

To avoid having this happen on an annual basis Apple would need to update the deferral logic.  I’ve filed FB16108783 with Apple, and I encourage you to do the same.  The current request is:

Major Deferrals decide if a computer can go between major OS versions (i.e. can the computer go from macOS 14 to macOS 15?) but it doesn’t decide the minor version available. Instead it uses the Minor deferral, if set, to decide which minor version of the upgrade is allowed (i.e. can it go from macOS 14 to macOS 15.1.1 or macOS 15.2?).

With this in our scenario of 90 days major/14 day minimum computers would upgrade directly to macOS 15.1.1 and assume similar security patches.

Thanks to Adam Codega and Eric Carr for assistance writing this!

Undocumented change in Jamf Pro 11.11 limits policy logs

In Jamf’s November 2024 Jamf Pro 11.11 update Jamf silently added in a 25 KB limit to policy log output. This will limit the your ability to troubleshoot scripts that fail to run with an output more than 25 KB.

Jamf support notes that this is to prevent “server degradation”. There is no public documentation on the new limitation, nor is it included in the Jamf Pro 11.11 release notes. Jamf’s suggestion is to modify scripts to limit output or send any additional data to a local log file instead.

Jamf Premium cloud customers can request this limit be increased.

Credit to Eric Carr of Mann Consulting for identifying this issue.

Testing

Testing this is quite simple, create a policy that uses this script which outputs ~27 bytes of data 1,000 times:

#!/bin/zsh

for i in {1..1000}; do
  echo "ThisStringIsAbout25Bytes $i"
done

Run the policy and check the log output. As shown in the image below you’ll see the log output is truncated at 25KB with …Output Truncated…

Next steps

Unless you’re on cloud premiums your options are limited, but include:

  • Setup external logging to Datadog or Splunk.
  • Rewrite the log files located in /Library/Application Support/JAMF/tmp/ before Jamf submits them.
  • Reduce your logging statements in scripts.

How to run unsigned apps in macOS 15.1

Apple uses code signatures to verify app are created by a specific developer and haven’t been tampered with. This is done through Apple’s Gatekeeper process which blocks execution of known bad code or code with no signature at all. In versions of macOS prior to 15.1 you bypass this block by going to System Settings > Privacy and Security after an app is blocked allow it to open.

Apple introduced a change in macOS 15.1 that blocks running all unsigned code. This can be an issue for those wishing to run Open Source applications where the $99/year developer fee may not be feasible. It’s not clear if this change is on purpose or a bug, but you can work around this with a a simple terminal command… and you don’t even need to be admin to do it!

Note: Gatekeeper and code signing is a very important security mechanism in macOS, bypassing it may result in harmful code execution on your computer. Before you exempt an application from Gatekeeper you should be confident of it’s source as well as decide if it’s worth risking the integrity of your system.

Gatekeeper uses the extended attribute com.apple.quarantine to decide if a file should be checked. Manually removing this flag will tell Gatekeeper to skip checking the application on launch and let it execute. This will allow for running unsigned applications again without disabling System Integrity Protection.

First we need to find an app that’s not signed, in this case we’re using Alacritty as our example now.

After you’ve downloaded Alacritty and dragged it into your Applications folder, double click on it to run. You’ll get the following error:

Even going to System Settings > Privacy and Security and clicking open anyway will result in the same error.

Next open Applications > Utilities > Terminal, once you get a command prompt enter the following and press return.

xattr -r -d com.apple.quarantine /Applications/Alacritty.app

Try opening Alacritty from your Applications folder again, it should load without an issue!

Modify the command to use the path of the app you want to remove the quarantine extended attribute from. Note that you have to have write access to the file to remove the quarantine flag.

Tricking require an admin password to access system-wide settings

Summary

macOS has a setting under System Settings > Security and Privacy > Advanced called “Require an administrator password to access system-wide settings” (I’m going to call it “require admin setting” from here out). The help section describes this option as “Prevent users from changing locked system settings without an administrator’s password.” Unfortunately the setting doesn’t work as documented, and it can be set to “enabled” while still allowing standard users to modify system-wide settings.

You can see an example of what this looks like in this video.

On a fresh computer out of box the system administrator password is already required to unlock many system wide preference panes, like network for example. Enabling the require admin setting simply prevents that authentication from being shared with another pane. For example if an admin account unlocks the battery preference pane then leaves the computer a standard account could modify the network preference pane. In this write up we’re going to go over methods on how this setting can be modified so that both system settings and most compliance checks will incorrectly assume an administrator’s password is required to change settings, when in fact either a standard account’s password or no password at all will modify them.

A number of compliance benchmarks like CIS, STIG and NIST recommend enabling this feature to avoid standard accounts from changing some settings, like disabling content filtering or changing DNS settings. 

  • macOS 14 Sonoma STIG: “The system must be configured to require an administrator password in order to modify the systemwide preferences in System Settings. Some Preference Panes in System Settings contain settings that affect the entire system. Requiring a password to unlock these system wide settings reduces the risk of a nonauthorized user modifying system configurations.”
  • CIS Apple macOS 14 Sonoma Benchmark, control 2.6.8: “By requiring a password to unlock system-wide System Preferences, the risk of a user changing configurations that affect the entire system is mitigated and requires an admin user to re-authenticate to make changes. Users will need to enter their password to unlock some additional preference panes that are unlocked by default like Network, Startup and Printers & Scanners. ​​Run the following command to verify that accessing system-wide preferences requires an administrator password.”

Notes:

This has been reported to Apple Platform Security and it’s been considered a “Feature Request”. FB13705715 has been filed with Apple as a feature enhancement.

This has been reported to the macOS Security and compliance project and fixed.

This has been reported to the CIS team to update checks and remediations.

What the require admin setting changes

First let’s look at what the setting does, when enabling it in System Settings the authorizations database is edited for a number of system setting panes to set the “shared” key to the value “false”.

These preference panes are:

  • system.preferences
  • system.preferences.energysaver
  • system.preferences.network
  • system.preferences.printing 
  • system.preferences.sharing
  • system.preferences.softwareupdate
  • system.preferences.startupdisk
  • system.preferences.timemachine

To validate what the setting changes you can use the following command with the setting both on and off, you’ll see the shared key change from true to false.

Command:

/usr/bin/security authorizationdb read system.preferences.network

Output (shared key in bold):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>allow-root</key>
	<true/>
	<key>authenticate-user</key>
	<true/>
	<key>class</key>
	<string>user</string>
	<key>group</key>
	<string>admin</string>
	<key>modified</key>
	<real>731951705.60508299</real>
	<key>session-owner</key>
	<false/>
	<key>shared</key>
	<false/>
	<key>timeout</key>
	<integer>2147483647</integer>
	<key>tries</key>
	<integer>10000</integer>
</dict>
</plist>

Apple’s authorizations documentation on the shared key is as follows, note that there is nothing in it about requiring an admin password: 

If shared is set to true, then the Security Server marks the credentials used to gain this right as shared. The Security Server may use any shared credentials to authorize this right. For maximum security, set sharing to false so credentials stored by the Security Server for one application may not be used by another application.

So according to Apple’s documentation it prevents a user from entering a password in one preference pane and sharing that authorization with another preference pane after.

Tricking the require admin setting

Reviewing the output in the previous section you’ll notice there are some other keys present that aren’t modified when enabling or disabling the require admin setting. Specifically the following are of interest to us:

  • group: The group of users allowed to modify settings after authentication. (Default admin)
  • session-owner: true/false if the current session owner is allowed to modify the setting. (Default false)
  • authenticate-user: true/false if authentication is necessary before making modifications. (Default true)
  • timeout: The credential used by this rule expires in the specified number of seconds. For maximum security where the user must authenticate or consent every time, set the timeout to 0. (default 2147483647)
    • Note: Timeout only applies when the shared key is set to true

So for example setting the key “group” to the value “everyone” will allow any user on the system to modify settings or setting the “session-owner” key to “true“ will allow the currently logged in user to modify System Settings. You will need to modify authorizations for both the root system.preferences and the individual pane, otherwise the authorizations for the system.preferences will take precedence.

Some examples of false pass configs. Once applied, sign in as a standard user, open System Settings > Network and modify the DNS server.  When prompted for “Administrator credentials” just enter the standard username and password and the settings will be applied. You’ll need to quit and re-open 

First save these snippets as system.preferences.changes.plist file then run the following command to apply them. 

sudo /usr/bin/security authorizationdb write system.preferences.network < system.preferences.changes.plist

sudo /usr/bin/security authorizationdb write system.preferences < system.preferences.changes.plist

Any user (standard or admin) can edit the network preferences with their password:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>authenticate-user</key>
	<true/>
	<key>class</key>
	<string>user</string>
	<key>group</key>
	<string>everyone</string>
	<key>session-owner</key>
	<false/>
	<key>shared</key>
	<false/>
</dict>
</plist>

The currently logged in user (standard or admin) can edit the network preferences without any authentication, even though admin group is required:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>authenticate-user</key>
	<false/>
	<key>class</key>
	<string>user</string>
	<key>group</key>
	<string>admin</string>
	<key>session-owner</key>
	<true/>
	<key>shared</key>
	<false/>
</dict>
</plist>

Properly requiring admin to unlock system-wide settings

If you’d like to properly require that an administrator is required to unlock system-wide settings then you’ll need to make sure all the following settings are set for each preference pane, in this example we’re only setting the root system.preferences and system.preferences.network

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>authenticate-user</key>
	<true/>
	<key>class</key>
	<string>user</string>
	<key>group</key>
	<string>admin</string>
	<key>session-owner</key>
	<false/>
	<key>shared</key>
	<false/>
</dict>
</plist>

Breaking the require admin setting

It’s also possible to put the authorizations in a state where the setting is no longer able to be toggled on/off. This will cause a failure and the slider in system settings will never stay “on” when you enable it. This occurs when the “class” key is set to a value other than “user”, in this example we’re setting the “class” key to “allow” which will always allow anyone to modify this setting:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>class</key>
	<string>allow</string>
</dict>
</plist>

Why change this setting?

If you’re asking “This setting requires admin to change, what’s the big deal?” then great question! There are a number of cases this setting could be changed without organizational knowledge:

  • Another current or previous administrator followed steps online to allow standard users to modify printers or modify network settings.
  • An application or application installer that runs as an admin installer modified the database without your knowledge.

For some organizations these are valid use cases and they should be taken into account.

How did you end up going down this rabbit hole?

I work at Mann Consulting, we co-manage Jamf instances for customers with high security needs. When implementing CIS Controls we found some computers weren’t providing us with consistent results. We found this was a result of changes made by a previous consulting firm that had since been removed from Jamf but the setting remained changed on the computers.

Special thanks to Bob Gendler for assistance in testing, documenting, providing feedback and listening to me curse this setting.

The following site also provided insights into all the setting available for authorizations.

Jamf Pro Framework Not Installing or Redeploying

Starting on or around Monday June 26th we recently ran into some issues where the Jamf Pro Binary located at /usr/local/bin/jamf was missing on newly enrolled computers. The computers would be MDM enrolled but and would receive configuration profiles but the Jamf Management Framework, including Self Service and the jamf binary would be missing. Because of this check-in and inventory were not fully taking place.

This was easily reproducible on computers by using the API to issue the redploy command curl -X POST "https://COMPANY.jamfcloud.com/api/v1/jamf-management-framework/redeploy/{id}".

After further review we found errors in the install.log during enrollment:

[******/com.jamfsoftware.enrollment.dep.quickadd] Failing installation after receiving error: Error Domain=PKInstallErrorDomain Code=100 "Authorization is required to install the packages." UserInfo={NSLocalizedDescription=Authorization is required to install the packages.}

After some digging we identified there was a Configuration Profile with a Restrictions payload that enabled the setting “Require admin password to install or update apps“. Excluding a computer from the this group or unchecking this box and reinstalling resulted in the Jamf Management Framework to properly install.

It’s unclear if this was caused by the macOS 13.4.1 update or if changes to Jamf in the 10.47 upgrade caused this issue. I’ll post more after testing. For now if you use restrictions to prevent standard users from installing from the Appstore we recommend scoping this profile to computers after their enrollment is over a day ago.

Update: This issue also blocks the installation of Jamf App Catalog apps. We tested with Discord, at 15:17:00 Jamf Pro issued the InstallEnterpriseApplication - Discord - 0.0.275 command to a device, after which we saw the following error in the logs:

2023-07-03 15:17:10-07 MacBook-Pro installd[21959]: PackageKit: Install rejected with error: Error Domain=PKInstallErrorDomain Code=100 "Authorization is required to install the packages." UserInfo={NSLocalizedDescription=Authorization is required to install the packages.}

Capturing Jamf Protect Diagnostics to S3

While it doesn’t happen often at all sometime your staff will have issues performance issues with Jamf Protect. This was apparent for us recently with an issue that was patched in 3.1.4.425, which was compounded by a Unified Logging filter that generated a lot of information. In the process of gathering logs for support we realised that the shell scripts they were providing weren’t easy for our employees to run/save/send to us in a timely manner. The resulting script and workflow came of this to automatically capture the logs and upload them to a write only S3 bucket

The Write Only S3 Bucket

First you need to make a S3 Bucket and assign a IAM user Put only rights to it. The following permissions should accomplish this, place S3BUCKETNAME with your bucket name. Please test and validate it’s correctly restricting to write only.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::S3BUCKETNAME/*"
            ]
        }
    ]
}

The Script

You can find the script used on our public GitHub repo at https://github.com/isaacatmann/Jamf-Protect-Diagnostics-Upload – Upload this as a script in your Jamf Instance.

The Policy

We found this works best as a Self Service items so that any staff impacted by issues can immediately report when they occur. The policy should have the following settings

GeneralPayloadsScope
Trigger
Self Service

Frequency
Ongoing
Scripts
Jamf Protect Diagnostics Upload.sh
Parameter 4: S3 Write only IAM Key
Parameter 5: S3 Write only IAM Secret
Parameter 6: S3 Bucket Name
Targets
All Computers

Security Note: The IAM Key and Secret will be visible to any user on the computer when the script is running. You should make sure you’re okay with this key being exposed and that it has the correct limitations in pace.

Employee Interaction

When run your employees will be asked a couple question about the issues they’re experiencing. These answer will be included in the zip file that is uploaded to S3.

The Resulting Zip File

You should now have a Zip file in your S3 bucket that has all the information Jamf Support typically asks for.