> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ultra.security/llms.txt
> Use this file to discover all available pages before exploring further.

# MDM Deployment (Jamf)

> Deploy Ultra across your fleet via Jamf Pro for zero-touch enterprise setup

Deploy Ultra across your organization using Jamf Pro. When deployed via MDM, Ultra automatically configures all detected MCP clients, migrates existing server configurations, authenticates with Ultra Hub, and attributes each gateway to the correct employee via SCIM identity resolution. No user interaction required.

## Prerequisites

Before deploying Ultra via MDM, ensure these are configured:

* **Jamf Pro** with macOS device management
* **Ultra Hub** organization with at least one workspace
* **SSO** configured for your organization ([setup guide](/hub/sso))
* **SCIM** directory sync provisioning users from your IdP ([setup guide](/hub/scim))
* **Deploy key** created in Ultra Hub ([setup guide](/hub/deploy-keys))

<Note>
  SCIM provisioning is required for per-user identity resolution. Without it, gateways are attributed to the admin who created the deploy key. SSO ensures users can authenticate independently if needed.
</Note>

## Setup

<Steps>
  <Step title="Create a deploy key in Ultra Hub">
    Follow the [Deploy Keys](/hub/deploy-keys) guide to create a key scoped to the workspace your fleet should link to. Copy the `dk_...` key immediately -- it is shown only once.
  </Step>

  <Step title="Upload the Ultra package to Jamf">
    Download the latest signed and notarized `.pkg`:

    ```
    https://get.ultra.security/latest/Ultra-macOS.pkg
    ```

    To pin a specific version:

    ```
    https://get.ultra.security/v{VERSION}/Ultra-{VERSION}-macOS.pkg
    ```

    In Jamf Pro, go to **Settings > Packages** and click **New** to upload the `.pkg`.
  </Step>

  <Step title="Create the Configuration Profile">
    Download the sample Configuration Profile:

    ```
    https://get.ultra.security/Ultra-macOS.mobileconfig
    ```

    In Jamf Pro, go to **Configuration Profiles > New** and upload the `.mobileconfig` file. You can use either upload method:

    * **Application & Custom Settings** — select the payload type and upload the file
    * **Upload** (raw mobileconfig) — upload the `.mobileconfig` directly without selecting a payload type

    Both methods are fully supported. Customize the following keys:

    | Key         | Value               | Description                                  |
    | ----------- | ------------------- | -------------------------------------------- |
    | `AutoSetup` | `true`              | Enables zero-touch setup                     |
    | `DeployKey` | `dk_...` (your key) | Headless Hub authentication                  |
    | `UserEmail` | `$EMAIL`            | Per-device user identity from Jamf inventory |

    <Note>
      The `$EMAIL` variable is a Jamf payload variable that auto-populates with the device owner's email from Jamf inventory. This requires user-device affinity to be configured (e.g., via SSO login during enrollment).
    </Note>

    **Optional keys:**

    | Key                 | Value  | Description                                              |
    | ------------------- | ------ | -------------------------------------------------------- |
    | `HubURL`            | URL    | Hub URL override (default: `https://hub.ultra.security`) |
    | `DisableAutoUpdate` | `true` | Disable self-updates to manage versions via Jamf         |
    | `UserExternalID`    | string | IdP external ID as secondary identity signal             |
  </Step>

  <Step title="Create a deployment policy">
    In Jamf Pro, go to **Policies > New**:

    1. Add the Ultra package under **Packages**
    2. Scope to your target Smart Group or computers
    3. Set trigger to **Enrollment Complete** (recommended) or **Recurring Check-in**
    4. Ensure the Configuration Profile is scoped to the same targets
  </Step>

  <Step title="Deploy">
    Ultra installs silently on target machines. No user interaction is required at any point.
  </Step>
</Steps>

## How It Works

<Tabs>
  <Tab title="User Logged In">
    When a user is logged in at install time:

    ```
    Jamf installs .pkg
      -> postinstall detects AutoSetup=true from Configuration Profile
      -> ultra install --all (configures all MCP clients)
      -> auto-links gateway to Hub via deploy key
      -> Hub resolves UserEmail against SCIM directory
      -> ultra migrate --all --yes (migrates existing servers)
      -> gateway visible in Hub immediately
    ```

    The gateway appears in the Hub dashboard as soon as installation completes, before the user opens any MCP client. When the user later opens a client, `ultra start` detects the existing link and begins syncing policies, telemetry, and guardrails.
  </Tab>

  <Tab title="DEP Enrollment (No User)">
    When the `.pkg` installs before any user has logged in (Automated Device Enrollment):

    ```
    Jamf installs .pkg
      -> postinstall detects no user session
      -> installs one-shot LaunchAgent
      -> user logs in for the first time
      -> LaunchAgent runs ultra install + migrate
      -> auto-links gateway to Hub via deploy key
      -> LaunchAgent self-removes
    ```

    The gateway links to Hub during the `ultra install --all` step, so it appears in the dashboard as soon as the LaunchAgent runs.
  </Tab>
</Tabs>

## Identity Resolution

Ultra uses SCIM directory sync to attribute each gateway to the correct employee. The resolution chain:

1. **Jamf** populates `UserEmail` with the device owner's email via the `$EMAIL` payload variable
2. **Ultra** sends this email to Hub during gateway link and on every heartbeat
3. **Hub** matches the email against the SCIM-provisioned user directory
4. If matched, the gateway is attributed to that user for audit, policy, and RBAC

### Unresolved Identity

If the email doesn't match a SCIM user (e.g., the user hasn't been provisioned yet, or the Jamf inventory is incomplete):

* The gateway **still links and works normally**
* It is flagged as **Unresolved Identity** in the Hub dashboard
* On subsequent heartbeats, Ultra re-sends the device identity
* When the match succeeds (e.g., after the user is provisioned in SCIM), the gateway **auto-resolves** without any manual intervention

<Note>
  A small number of devices may have missing Jamf inventory data if users don't complete the enrollment setup script. These gateways will show as "Unresolved Identity" until the inventory is corrected or the user is provisioned.
</Note>

## Managing Updates

By default, Ultra checks for updates every 24 hours and self-updates. For environments where you control rollout timing:

* Set `DisableAutoUpdate` to `true` in the Configuration Profile
* Use Jamf **Patch Management** or a **Smart Group** (e.g., "Ultra version \< X.Y.Z") to deploy new `.pkg` versions on your schedule

The `.pkg` at `https://get.ultra.security/latest/Ultra-macOS.pkg` always points to the current stable release.

## Configuration Profile Reference

All keys use the `com.ultra-security.ultra` preference domain.

| Key                 | Type    | Default                      | Description                                               |
| ------------------- | ------- | ---------------------------- | --------------------------------------------------------- |
| `AutoSetup`         | Boolean | `false`                      | Zero-touch setup (auto-install clients + migrate servers) |
| `DeployKey`         | String  | -                            | Deploy key for headless Hub authentication                |
| `UserEmail`         | String  | -                            | Device user's email for SCIM identity resolution          |
| `UserExternalID`    | String  | -                            | IdP external ID (secondary identity signal)               |
| `HubURL`            | String  | `https://hub.ultra.security` | Hub URL override                                          |
| `DisableAutoUpdate` | Boolean | `false`                      | Disable self-updates                                      |

## Verifying Deployment

On a managed machine:

```bash theme={null}
# Check Ultra is installed
ultra version

# Check managed preferences are applied
defaults read com.ultra-security.ultra

# Check which clients are configured
ultra install --list

# Check postinstall log
cat /tmp/ultra-postinstall.log
```

In the Ultra Hub dashboard:

* Navigate to **Gateways** to see deployed devices
* Each gateway should show the assigned employee (from SCIM)
* Gateways with missing identity data show an **Unresolved Identity** badge

## Troubleshooting

**Ultra not in client configs after install:**

* Check `/tmp/ultra-postinstall.log` for errors
* Verify the Configuration Profile is installed: `profiles show -type configuration`
* Run `ultra install --all` manually to configure clients

**Gateway shows "Unresolved Identity":**

* Verify the user is provisioned in your IdP and synced via SCIM
* Check that Jamf has the correct email in the device inventory (User & Location)
* The gateway will auto-resolve on the next heartbeat once the email matches a SCIM user

**LaunchAgent did not run on first login:**

* Check if plist exists: `ls /Library/LaunchAgents/com.ultra-security.ultra-setup.plist`
* Check agent log: `cat /tmp/ultra-setup-agent.log`
* Run manually: `ultra install --all && ultra migrate --all --yes`

**Deploy key authentication fails:**

* Verify the key hasn't been revoked in Hub dashboard (Settings > Security)
* Check the key hasn't expired
* Ensure `DeployKey` is set correctly in the Configuration Profile: `defaults read com.ultra-security.ultra DeployKey`

**Managed preferences not picked up:**

* Verify the profile is deployed: `defaults read com.ultra-security.ultra`
* If `defaults read` returns nothing but the profile is installed, check the plist file directly:
  ```bash theme={null}
  /usr/libexec/PlistBuddy -c "Print" "/Library/Managed Preferences/com.ultra-security.ultra.plist"
  ```
* Ultra reads managed preferences at startup. Restart the MCP client to pick up changes.
* Ultra supports multiple Jamf profile structures automatically, including raw mobileconfig uploads where keys are nested under `PayloadContent`.
