Why we need Privileges or why Apple needs to get better at admin-less actions
Back in 2019-2020, I blogged about using Privileges as it was somewhat freshly out in the Apple Community. It worked well for certain things but had some issues, namely:
- End-users couldn’t be prompted for the reason for the escalation.
- Admin demotion on launch didn’t always work effectively.
- Logging and alerting of escalation requests didn’t work very well.
- Various little items
Now that SAP has released Privileges 2.X of their software, a lof of these previous issues I was having with our deployment back in 2019-2020, have been resolved. I have also started working at $currentJob, which have the same reoccurring struggle: Needing Admin-less access on macOS and Audits. In every audit I have ever been in, they ask, “Do you restrict admin access on macOS?” So, getting us to easily pass this question with a confirmation of approval while still allowing end-users to promote themselves is the best of both worlds.
I am not a fan of pure admin-less, as macOS is not built or intended to be used in a way where the end user doesn’t have admin access to perform some functions. Privileges creates an easy middle-ground of the best of both worlds.
Why does Apple do the way they do?
Apple requires an end-user to have admin access to several things, mainly end-user-beneficial services. Apple has generally not taken the stance of relaxing any of these permission requirements but locking them down even further, which makes life as both an admin and an end-user quite tricky.
Additionally, adjusting what can be done with or without admin access is impossible. Yes, you could add a user to the lpadmin
group, but for most situations, it is impossible to restrict some of these with admin access or provide access for admin-less users. For example, Software Updates (EG: macOS 15 Sequoia) shouldn’t require Administrator access—similar to Feature and Quality updates on Windows.
Arguably, anything network-related (e.g., Changing DNS, Changing Network SSIDs, setting a static IP Address) should not require administrator access to execute. This type of elevation is not needed for any user-space configurations. It would be nice if this could be separated out of the system-level configurations.
For a more comprehensive list of required administrative actions, see below.
Actions on macOS That Require Administrator Access
1. User & Account Management
- User Accounts
- Creating, deleting, or modifying user accounts
- Changing user roles (Standard ↔ Admin)
- Resetting passwords for other users
- Modifying parental controls
- Login & Authentication
- Managing login items for all users
- Enabling/disabling automatic login
- Modifying FileVault encryption settings
- Approving biometric (Touch ID) system-wide changes
2. System & Security Settings
- Security & Privacy
- Configuring Gatekeeper settings (allowing apps from “Anywhere”)
- Modifying Privacy & Security settings (Full Disk Access, Accessibility, etc.)
- Enabling/disabling System Integrity Protection (SIP)
- Modifying Firewall rules and network permissions
- Software & Updates
- Installing system updates via System Settings → Software Update
- Installing/removing system-wide apps in
/Applications
- Approving system extensions (KEXTs)
- Modifying system-wide LaunchDaemons or LaunchAgents
- System Configuration
- Modifying NVRAM/PRAM and SMC settings (via recovery mode)
- Enabling/disabling Time Machine backups
- Changing system-wide environment variables
- Using the console.app or the
log
command at the system level
3. Network & Connectivity
- Networking
- Changing system-wide Wi-Fi, Ethernet, or VPN configurations
- Modifying Proxy settings
- Setting custom DNS servers
- Remote Access
- Enabling/disabling Remote Login (SSH)
- Configuring Screen Sharing, Remote Management (ARD)
- Internet Sharing & Hotspots
- Enabling/disabling Internet Sharing
- Modifying Personal Hotspot settings
4. File System & Storage Management
- Filesystem Permissions
- Modifying system files in
/System
,/Library
, or/bin
- Changing ownership or permissions of system files (
chmod
,chown
)
- Modifying system files in
- Disk & Volume Management
- Mounting/unmounting encrypted drives
- Formatting, partitioning, or erasing drives (
diskutil
) - Managing APFS snapshots or encrypted volumes
- Keychain & Certificates
- Installing or modifying root certificates
- Modifying system-wide keychains
5. Device & Hardware Control
- Peripheral & Hardware Access
- Installing/removing drivers (e.g., s, USB devices)
- Allowing USB accessories in macOS Ventura+ (USB Restricted Mode)
- Apple Silicon (M1/M2) & T2 Security Settings
- Modifying Startup Security Utility settings
- Disabling Secure Boot or enabling external booting
- Virtualization & Development
- Enabling Hypervisor framework for virtual machines
- Running macOS inside a VM (e.g., VMware, VirtualBox)
6. Enterprise & IT Administration
- MDM & Configuration Profiles
- Installing/removing Mobile Device Management (MDM) profiles
- Applying system-wide configuration profiles (
profiles
CLI) - Installing/removing enterprise VPN profiles
- Software Deployment & Automation
- Installing system-wide software via command-line package managers (e.g.,
brew
affecting/usr/local/
) - Running automation scripts that modify system settings (
sudo
)
- Installing system-wide software via command-line package managers (e.g.,
- Remote Management & Security Policies
- Enforcing corporate policies via Jamf, Intune, or other MDM solutions
- Applying remote lock/wipe via Find My Mac
Notable Exceptions (That Do Not Require Admin)
Some actions appear to require admin but do not:
- Installing apps in
~/Applications
(user-specific) - Using AirDrop, Bluetooth, or Wi-Fi (unless restricted by MDM)
- Adjusting display settings, Dock preferences, or menu bar settings
- Running most command-line tools without modifying system files
Setting up checks and balances
So, to get the best of both worlds, we need to determine several things.
- We need a system or service that monitors activity on macOS. This could be a Log Shipper, Behavior Analytics, MDM, or some other software (e.g., DTEX, JAMF, etc.).
- We need easy alerting and logging based on the actions and promotion/demotion requests.
- This can be accomplished with Privileges and a shell script (or python, go, etc).
- We need an assurance tool to enforce admin-less activities.
- This will ensure that individuals are not trying to work around the system.
- We need some form of verification that assurance, files and other processes are working together. This way, we can determine if someone is faking information through the device assurance tool or less intrusive device assurance.
So how will we accomplish that?
Deploying DataDog API Keys in a secure fashion
So, first, we must set up a way to securely deploy our DataDog API key. There are a few methods you could use to accomplish this:
- Use JAMF to distribute it through a script
- Deploy the script as part of a no-package file that executes the script
- Adding the API Key to the Keychain
- Using a secrets vault to call the API key from 1Password, HashiCorp, GCP, or AWS.
We would prefer reliability here, which means that the API key needs to be on the device for it to work reliably. The risk of the API Key is also quite low, as all it can do is post content into a DataDog instance attached to a specific tag/service.
|
|
What this does is:
- Push the API key into Keychain and call it “DataDog API”
- This will allow us to call the Datadog API key in scripts that we need to use to upload the log file without putting in “clearer” text.
But then, how will we handle network connectivity issues? Check out the section below for more information.
Deploying the Privileges PKG
Previously, in versions before 1.5.4, you would likely have to bundle the .app to include the launch agent or add any additional functionality you wanted with the tool. Now, with 2.X>, this is being done automatically, so there is little overhead other than pushing out the tool.
We will not discuss in depth how to deploy a PKG file via an MDM, as it depends on each MDM service.
Demoting Administrators to Users immediately on installation
Now, with deploying privileges, one of the few issues remains that users won’t automatically get demoted from Administrator to Standard Users, at least not immediately if you were to wait for those users to reboot or click on the app/dock icon. So, we want to deploy a script that will automatically demote the user to Standard User.
Here are some key deployment notes. Using JAMF is easy enough. We just drop a script in the same policy as the package installation and mark it for “after” run. If you are using other MDMs or package repositories (EG: Munki), here are a few options:
- If using Munki, you could add this to a post-install script, or you could couple a
requires
key with the packages, use manifest, etc. There are several different ways to tackle this. - Kandji and Mosyle also support the idea of a “post-install” script, which would run immediately after the package is installed. You could also use a Blueprint if you need to install multiple packages in a single run.
- If using Intune, you would need to wrap the package inside another package to deploy this effectively. This is not a recommended method, as it adds several layers of confusion. Alternatively, you could deploy both applications separately and then use configuration scripts to manage the setup. Again, this is a bit more confusing.
Ultimately, it excludes the administrator and root user and automatically downgrades the logged-in user to admin utilizing PrivilegesCLI -r
.
When writing this, I was having some issues getting the Privileges output to read correctly on the demotions. However, I will work on getting this updated and improved so that the script properly exits and validates.
|
|
Deploying an on-action alert for Privileges
So, it’s helpful for us to understand not only why an end-user needs to be promoted to admin but also the time, date, username, machine, and serial number of the device. It is also helpful to have the expected demotion time to cross-check if the demotion occurred at all (whether on time or before the expected time frame).
So, let us go over the script below.
- Configure the DataDog API Endpoint. Note that this one specifically uses the EU endpoint and would need to be updated for the US or other locations based on your individual needs.
- We will pass the reason from the Privileges.app into the on-action script through
$3
, and if this fails or isn’t passed, use the log command as a backup to process and find the reason. We will also wait 5 seconds to ensure that the log command can see the contents of the SAP output. - We will check if the user is currently an admin while this script is running to ensure that the log command can work under the admin run.
- Check the install.log commands on demotion and output any new installations (as this file can be read without admin logs).
- We will sanitize the reason and the log files to make them difficult to exploit through command redirections or hacks (be aware that this isn’t bulletproof).
- We add tags to the HTTP post command to differentiate between a privilege escalation and a privilege demotion.
- Then, finally, send that data to DataDog.
|
|
Deploying Privileges Mobile Configuration / JSON Schema
For JAMF, JSON Schema configurations seem to be the way to manage the configurations going forward. We have an internal one, but thankfully, Tony Young (@tonyyo11) has been creating one himself, which is shown below (for Privileges v2.2).
This makes it substantially easier to deploy the Mobile Configuration profile.
|
|
For a comparison, our configuration in plist format for Privileges with the above code is:
|
|
Adding Privileges to Dock
This is fairly straightforward. The main user experience with Privileges is either in the menu bar or in the dock, and we want this to be front and center and easy for users. Given that Apple has included a notch on the main laptop displays, which causes icons to get cut off, the dock is the better option. So we need to add it automatically to the employees’ docks without interrupting or breaking the experience for their existing dock.
Side note: if you experience menu bar and notch issues, I highly recommend Ice.app (Open Source and Free, but you should donate) to help you manage the menu bar.
Below is a script that should help add the Privileges app to the dock. It’s straightforward and based on existing code that works.
|
|
Configuring JAMF EAs
If you need a JAMF Extension Attribute in place of using something in Datadog (or your equivalent SIEM) or to complement it, you can utilize one of the commands in the DataDog script to provide this into JAMF. This coincidentally was also requested on #privileges on MacAdmins right after I posted the previous script, so it was an easy addition.
Ultimately, all this does is query the log for anything about SAP Privileges, and if needed, you could shorten this time frame to a day, week, or some other time frame. Then, we tail the last 5 lines and provide that as an EA Result. The resulting output should look something like this (these were the reasons I kept escalating when trying to promote myself for the DataDog setup):
|
|
The actual JAMF EA script is below:
|
|
Configuring Kolide to Verify Administrator Status
So now that we have Logging and Alerting in place, what do we do about posture checking and enforcement?
Kolide can easily play a role in this when accessing your own internal services, allowing end-users to efficiently self-resolve and remediate the non-admin requirement on their device. The frequency of this, however, can cause some slight experience issues, such as an increased waiting time to log in to a SaaS service.
|
|
The exact process, to some extent, could also be done through Crowdstrike’s Indications of Compromise or Real-Time Response, which also use OSQuery.
Validating LaunchAgents, LaunchDaemons, and Files are loaded on the device
Using JAMF
Below are two extension attributes that would allow you to build smart groups and compliance checks based on whether the scripts that we have previously deployed exist on the device in a more rough manner. We don’t do SHA checking, for example, but this could easily be implemented into the code structure to allow for it.
|
|
|
|
Using Kolide
Personally, I believe user remediation and focusing on user-based self-service solutions are the way forward. I like Kolide better for this so that you, as an admin, can provide the tools for the end user to resolve their issues themselves. This builds both education and self-ownership of the issue in the employee. The only drawback to this method is pressure and time crunch. Then, Tech Support can help resolve this.
So, the best route is to build a check-in Kolide that helps with this and provides self-service remediation, including links to reset files or tools through a self-service portal (e.g., JAMF, Munki, Company Portal, etc.).
This check will validate that the installed Privileges LaunchDaemons and LaunchAgents are correctly placed in the specific spots and meet the expected file contents. If you need to update the contents of the check for a new file or additional items, you can use shasum -a 256 {filepath}
to obtain the shasum and copy bits of the code below to verify any extra files.
|
|
You can then set up documentation in Kolide that informs why this is being done and how to resolve the situation.
No Network Connectivity? No Problem?
While I have not tested this quite yet, this is the next step in the script’s evolution. We still need to understand the escalation reasons even if a network connection is not available (for example, being on an Airplane, purposely avoiding the network to “hide behavior,” etc.). This can potentially work with the Jamf EA agent, but it does not resolve the solution of sending this data to the SEIM.
To accomplish this, we would need to add a few items to the script and modify it to save content when unable to connect or ping an IP Address. A sample of this can be found below:
|
|
This should save some of the contents to a file. Obviously, the /tmp
folder will be cleared on reboot, so this is not the most adequate place to put the file contents. You should modify this to be in /Users/Shared/
or some other suitable location.
You would also need to add a launch agent that runs every X minutes or on every reboot to send that data to DataDog when connectivity is re-established.
An example LaunchAgent.plist file can be found below:
|
|
Summary & Resources
All the available code samples above are available at the following privileges-resources Github Link.
I would recommend stopping by #privileges on MacAdmins, and if you don’t have an account, you can sign up here.
Feel free to comment below or reach out to the channel above to discuss this.