This PR cleans up an old tool/windows-mdm-poc, that we no longer use or rely on. It is also an effort to minimze inline dependencies when unused.
12 KiB
MDM index
Knowledge transfer videos
-
Roberto's MDM knowledge transfer videos
- Google Drive
- Also on Loom -- search for
MDM knowledge dump
-
Marcos's Windows knowledge transfer videos
Protocol
Apple
-
Apple documentation for MDM
- Web version: https://developer.apple.com/documentation/devicemanagement
- YAML version: https://github.com/apple/device-management
- NOTE: documentation for upcoming/beta features is available in the YAML version first, look for branches.
-
Fleet's MDM glossary: https://github.com/fleetdm/fleet/blob/main/tools/mdm/apple/glossary-and-protocols.md
-
MicroMDM and NanoMDM wikis.
-
MacAdmins Slack, channels: #mdmdev, #declarative-management, #apple-feedback, #nudge, #swiftdialog
Windows
-
Enrollment protocol: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mde/5c841535-042e-489e-913c-9d783d741267
-
MDM protocol: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mdm/33769a92-ac31-47ef-ae7b-dc8501f7104f
-
Initial PoC PR's: MDM Server Programmatic Enrollment
Android
See the Android MDM documentation
Development
./Testing-and-local-development.mdhas many sections about setting up MDM and debugging specific featurestools/mdm/apple/troubleshooting.mdhas instructions to troubleshoot Apple MDM in hoststools/mdm/*contains many ad-hoc tools we've been adding to aid development, including but not limited to:- Servers to perform MDM migrations from different providers
- Tools to debug the ABM APIs
- Tools to import/export certificates and keys from the DB
Fleet specific features
Profiles and Declarations
For Windows, Apple and Android MDM, Fleet defines "profiles" as groups of settings that can be SyncML (Windows), XML (Apple), or JSON (Apple/Android).
Settings are defined per team and can be further targeted to hosts using labels.
Profiles and declarations can be uploaded via the UI/CLI by the IT admin. Additionally, Fleet automatically sends profiles to hosts as part of high-level UI actions. For instance, enabling disk encryption in macOS sends the relevant configuration to the host.
To determine the subset of profiles/declarations that should be applied to a specific host, we use the following approach:
- Ideal State: The "ideal state" of a host is calculated by combining team profiles with any label-based inclusions/exclusions using the
mdm_*_configuration_profilesandmdm_apple_declarationstables. - Current State: The "current state" of a host is tracked using the
host_mdm_*_configuration_profilesandhost_mdm_apple_declarationstables, which are updated based on MDM protocol responses and kept in sync via osquery (commonly referred to as "profile verification" or "double-check"). - Diff Calculation: We use set algebra to compute the difference between the ideal and current states—determining the profiles that need to be installed ("to install") and those that should be removed ("to remove").
This logic runs in two main places:
-
mdm_*_profile_managerCron Job: Runs every 30 seconds and performs the following actions:- Calculates the profiles to install/remove
- Enqueues the necessary commands
- Sends push notifications to the hosts
-
ds.BulkSetPendingMDMHostProfiles: This method is called to mark profiles and declarations as "pending." It's a lighter process than the cron job, only updating database records to reflect pending profiles in the UI, providing immediate feedback to users.
Profile/declaration verification (double check)
Osquery double checks are explained in good detail as part of their initial specs:
NanoMDM Integration for Apple MDM
NanoMDM handles the core protocol operations for Apple MDM. Fleet extends the protocol and adds custom handling to align with our desired workflows.
After NanoMDM processes a protocol operation, it allows for custom logic by implementing the CheckinAndCommandService interface. Our implementation can be found in the service layer.
4ff5f7a18a/server/service/apple_mdm.go (L2595-L2600)
Additionally, per request from management, we maintain a modified version of the NanoMDM repository under server/mdm/nanomdm/ to support Fleet-specific requirements.
MDM Lifecycle
While implementing MDM-specific features, we identified recurring patterns related to managing the "MDM connection" to the host. We refer to this as the "MDM lifecycle." A few examples:
- The MDM server is not always notified when a host unenrolls. As a result, we perform cleanup during host enrollment since it's impossible to reliably determine whether a host is enrolling for the first time.
- Special MDM actions are triggered when a host is deleted via the UI.
All lifecycle-related actions are implemented in the HostLifecycle struct. A great way to familiarize yourself with the different MDM actions is to search for the usages of the different HostActions we have.
We use the terminology "turn on" and "turn off" to align with the language used by the product group, which is generally associated with enrollment and unenrollment.
HostLifecycle might not contain all lifecycle events, and does not cover Android as of today (2025/12/22)
SCEP Renewals
MicroMDM has documented the intricacies of SCEP certificate renewals in detail: MicroMDM SCEP Documentation.
In Fleet, we issue certificates with a 1-year validity period. To renew certificates, we send a new enrollment profile via the InstallProfile command.
The command to install the profile is queued in the renew_scep_certificates job, which is part of the cleanups_then_aggregation cron schedule.
It's important to note that when sending a new enrollment profile, certain fields must remain unchanged. Apple has documented these restrictions here: Apple MDM Profile Restrictions.
Puppet module
The Puppet module is deprecated as of Fleet 4.66. It's maintained for backwards compatibility.
The implementation of the Puppet module is described in detail at: ee/tools/puppet/fleetdm/CONTRIBUTING.md
MDM migrations
Windows MDM is more flexible when it comes to switching MDM servers, so MDM migrations are generally not a big deal.
Apple MDM is more strict, and we have built two different flows:
As of MacOS 26, iOS 26, and iPadOS 26, Apple has introduced a native MDM migration flow.
- The "regular" flow is what most customers will use, involve
fleetdguiding the user through the migration to perform manual steps. The user documentation for this flow is https://fleetdm.com/guides/mdm-migration - The "seamless" flow allows customers with access to their MDM database and ownership of the domain used as the
ServerURLin the enrollment profile to migrate the devices without user action. The user documentation for this flow is https://fleetdm.com/guides/seamless-mdm-migration- The proxy for the seamless flow lives in
./tools/mdm/migration/mdmproxy/ - The tool to extract data from MicroMDM lives in
./tools/mdm/migration/micromdm/touchless/
- The proxy for the seamless flow lives in
Disk encryption
Enabling and retrieving the disk encryption keys for a host behaves differently depending on the OS.
After the key is retrieved, it's stored in the host_disk_encryption_keys table. The value for the key is encrypted using Fleet's CA certificate, and thus can only be decrypted if you have the CA private key.
FileVault (macOS)
For macOS, disk encryption involves a two step process:
-
Sending a profile with two payloads:
- A Payload to configure how the disk is going to be encrypted
- A Payload to configure the escrow of the encryption key
-
Retrieving the disk encryption key:
- Via osquery, we grab the (encrypted) disk encryption key
- In a cron job, we verify that we're able to decrypt the key. It's necessary to verify if a key is encrypted because we could have grabbed a key generated by a third-party MDM, or an invalid key.
If we're not able to decrypt the key for a host, the key needs to be rotated. Rotation happens silently by:
- The server sends a notification to orbit, notifying that the key couldn't be decrypted.
- orbit installs an authorization plugin named Escrow Buddy that performs the key rotation the next time the user logs in.
- Fleet retrieves and tries to validate the key again.
BitLocker (Windows)
Disk encryption in Windows is performed entirely by orbit.
When disk encryption is enabled, the server sends a notification to orbit, who calls the Win32_EncryptableVolume class to encrypt/decrypt the disk and generate an encryption key.
After the disk is encrypted, orbit sends the key back to the server using an orbit-authenticated endpoint (POST /api/fleet/orbit/disk_encryption_key)
Load testing
osquery-perf supports MDM load testing for Windows and Apple devices. Under the hood it uses the mdmtest package to simulate MDM clients.
Documentation about setting up load testing for MDM can be found in the infrastructure loadtesting README
ADE
For a high-level overview of how ADE works please check the glossary
Below is a summary of Fleet-specific behaviors for ADE.
Sync
Sincronization of devices from all ABM tokens uploaded to Fleet happen in the dep_syncer cron job, which runs every minute, but can be configured by setting mdm.apple_dep_sync_periodicity to a duration string (e.g. "30s", "5m", "1h") in the config.
We keep a record of all devices ingested via the ADE sync in the host_dep_assignments table. Entries in this table are soft-deleted.
On every run, we pull the list of added/modified/deleted devices and:
- If the host was added/modified, we:
- Create/match a row in the
hoststable for the new host. This allows IT admin to move the host between teams before it turns on MDM or hasfleetdinstalled. - Assign the corresponding JSON profile to each host using ABM's APIs.
- Create/match a row in the
- If the host was deleted, we soft delete the
host_dep_assignmentsentry
Special case: host in ABM is deleted in Fleet
If an IT admin deletes a host in the UI/API, and we have a non-deleted entry in host_dep_assignments for the host, we immediately create a new host entry as if the device was just ingested from the ABM sync.
End user authentication
- Also known as: IdP integration, User account sync
- See MDM-end-user-authentication.md
macOS setup experience: bootstrap package
Before downloading the bootstrap package using GET /api/latest/fleet/mdm/bootstrap, the Apple device will make one or more HEAD requests to that URL. Fleet server does not support the HEAD request and will return 405 Method Not Allowed.
- Example script to wrap fleetd with a bootstrap package. This wrapper is useful for
manual_agent_installmacOS setup experience.