# Devices and MDM (Fleet) (https://docs.idra.zone/docs/admin/devices)

Device assurance policies, MDM sync with Fleet, Jamf, Intune and Kandji, and client certificates.

IdRa knows two kinds of devices:

- **Browsers**: every browser a person signs in from, listed on **Directory → Devices** and on each person's page. A browser is *managed* when an MDM record vouches for it, or when it presents a client certificate.
- **Managed hosts**: computers synced from an MDM (Fleet), with owner, platform, OS version, serial, disk encryption, failing policies and last seen.

Device checks only matter once you use them in a policy: create a device assurance policy, then add *Device assurance policy is any of …* to an [authentication policy](https://docs.idra.zone/docs/admin/policies) rule.

## Device assurance policies

**Security → Device Assurance → Policies**. Each policy targets one **Platform** and can require:

- **Minimum OS version** (the MDM-reported version when known; browser-reported versions are low assurance, macOS browsers always report 10.15.7);
- **Device is managed** (a match on the user's email and platform counts only if the integration has **Accept user + platform matches (weaker)** on; it's off for new integrations, and IdRa has no serial numbers for browsers yet, so without it this needs a client certificate);
- **Disk encryption is on** (reported by an MDM only) and **Firewall is on** (Jamf computers only: on other MDMs this never passes);
- **Screen lock is set**, offered only on iOS (needs a Jamf Pro integration) and Android (needs a Fleet integration). No MDM reports it for macOS, Windows, Linux or ChromeOS. An older policy that requires it there never passes until you save it again, which clears the requirement;
- **No failing MDM policies** (Fleet: every policy passes. Intune: the device is compliant, and one in its grace period doesn't count);
- **MDM check-in within (hours)**.

A minimum OS version also covers patch levels when the MDM reports the full version: `10.0.22631.4317` on Windows, `14.6.1` on macOS.

## What each MDM reports

| | Disk encryption | Firewall | Screen lock | Jailbreak | Failing policies |
|---|---|---|---|---|---|
| **Jamf Pro** computers | Yes | Yes | No | No | No |
| **Jamf Pro** iPhone, iPad | Yes | No | Yes | Yes | No |
| **Intune** | Yes | No | No | Yes | Compliance state |
| **Kandji** | Yes | No | No | No | No |
| **Fleet** | Yes | No | Android only | No | Yes |

On Intune and Fleet, to require a firewall or screen lock where this table says no, put the check in an Intune compliance policy or a Fleet policy, then require **No failing MDM policies**. The Jamf API client needs **Read Mobile Devices** for iPhones and iPads; without it, computers keep syncing and IdRa logs `device.mdm.partial_sync`.

Jailbreak status and the Android security patch level (Intune) show on **Directory → Devices**. They can't be required in a policy yet.

## What a denied person sees

When a rule denies someone at an app and meeting a device assurance policy would let them in, the denial page lists what to fix: for example, update the OS or turn on disk encryption. If the MDM doesn't report a check, the page tells them to contact you, because nothing on the device can change it. People denied for another reason, such as their group or network, see no device steps.

## MDM integrations

**Security → Device Assurance → MDM integrations → Add**: Jamf Pro, Microsoft Intune, Kandji or **Fleet**. IdRa reads device records from the MDM's API hourly, and on demand with the sync button (↻) on the integration's row, and matches them to people's browsers by serial, else by person and platform. Jamf Pro also syncs iPhones and iPads.

### Fleet

Fleet is optional; IdRa works the same without it.

1. **Connect:** enter the Fleet server URL (public https; private IPs and plain http are refused) and an API-only user's token (`fleetctl user create --api-only`). Observer is enough to sync; lock, unlock, wipe and refetch need Maintainer or Admin. The token is encrypted at rest. **Test connection** shows the Fleet version and the token's role.
2. **Sync:** hourly and on demand (↻), every host goes into **Directory → Devices → Managed hosts**. The owner is matched by Fleet's device mapping or IdP email. Unmatched hosts are listed as *Unassigned*; hosts removed from Fleet disappear on the next full sync.
3. **Webhook:** the add dialog shows a webhook URL once, `<BASE_URL>/api/hooks/fleet/<secret>` (**New webhook URL** replaces it). Point Fleet's failing-policies, host-status and activities webhooks at it for near-real-time updates. IdRa only reads host ids from the payload and re-reads those hosts from Fleet. On large fleets set the failing-policies webhook's `host_batch_size` (e.g. 100): bodies are capped at 1 MB.

What a Fleet host does in IdRa:

- **Policies:** a matched host vouches for its owner's browsers on the same platform (for **Device is managed**, see the setting above). A host with only the fleetd agent still reports posture but doesn't count as managed.
- **Risk:** a host is compliant when no Fleet policy fails and its disk isn't reported unencrypted. Losing compliance logs `user.device.compliance_change`, records a medium `mdm:device_noncompliant` risk signal (usable in entity risk rules) and notifies Shared Signals receivers.
- **Actions:** on **Managed hosts** (and the person's page): **refetch**, **lock**, **unlock** and **wipe** call Fleet, with a confirmation for lock and wipe. Each is logged as `device.fleet.<action>`. Lock and wipe need Fleet Premium with MDM (or scripts on Linux). A Mac's unlock PIN is shown once and never logged.
- **Disconnect** (delete the integration): its hosts leave IdRa and the browsers they vouched for stop counting as managed. Nothing changes in Fleet.

## Client certificates (mTLS)

If your MDM pushes a client certificate to devices, your TLS proxy can verify it and tell IdRa. Turn on **Client certificate (mTLS)** under **Security → Device Assurance → Client certificates**; a request then counts as managed when the proxy sends `X-Client-Cert-Verified: SUCCESS` and an `X-Client-Cert-Serial`. This only works with `TRUST_PROXY` set to `cloudflare` or `forwarded`; `railway` ignores these headers, because Railway's edge doesn't strip them.

  The proxy must strip both headers from incoming requests before setting them, or anyone can claim
  a certificate.

```txt title="Caddyfile"
tls {
  client_auth {
    mode verify_if_given
    trust_pool file /etc/caddy/mdm-ca.pem
  }
}
request_header -X-Client-Cert-Verified
request_header -X-Client-Cert-Serial
@cert expression {http.request.tls.client.serial} != ""
request_header @cert X-Client-Cert-Verified SUCCESS
request_header @cert X-Client-Cert-Serial {http.request.tls.client.serial}
reverse_proxy idra:3000
```

## Limits

- Matching is by serial, else by person + platform: one compliant host vouches for all of that person's browsers on the platform.
- Native device agents (Windows/macOS desktop MFA, desktop password sync) aren't part of IdRa.