mirror of
https://github.com/netbirdio/docs.git
synced 2026-10-30 08:29:03 +01:00
docs: group MDM policy keys by job and split delivery into per-platform pages (#1020)
* docs: document the MDM keys added since the page was written, and iOS The reference table listed 18 of the 23 keys the client recognises, and claimed a count of 16. Six keys were missing from every downloadable template as well, including lazyConnection, which the page already documented: - lazyConnection, disableAdvancedView, enableLocalMetrics, localMetricsAddress, allowRemoteJobs and debugBundleUploadURL are now in the reference table and in netbird.admx/.adml, io.netbird.client.plist, netbird-macos.mobileconfig, netbird-macos.sh and netbird-policy.reg. - Notes call out the two pairs that read as related but are not: disableMetricsCollection (anonymous telemetry) versus enableLocalMetrics (the client's own Prometheus endpoint), and disableAdvancedView being UI-only, so unlike its neighbours it never causes a request to be rejected. iOS and tvOS now have a section of their own. The channel is Apple's Managed App Configuration against bundle id io.netbird.app (io.netbird.app.tv on tvOS), with a new netbird-ios-appconfig.plist template and per-provider instructions. The section states what the policy reaches today: the app locks its interface and refuses configuration changes, while the tunnel engine runs in a Network Extension that does not receive the app configuration, so keys the engine applies to the connection are not enforced there yet. Two template defects found on the way: - netbird-macos.mobileconfig was not well-formed XML. Its header comment contained a double hyphen, which XML forbids inside a comment, so plutil -lint and any strict parser rejected the file an admin downloaded. - netbird-policy.reg had one LF-terminated line among CRLF ones; normalised, with the UTF-16LE encoding reg import requires preserved. Verified with npm run build and npm run lint:mdx, plus XML well-formedness on all five XML templates, bash -n on the shell template, and a cross-reference check that every string and presentation the ADMX references is defined in the ADML. * docs: iOS enforces every key; document when a change reaches the tunnel The iOS section was written while the policy stopped at the app: the network extension that runs the engine has its own preferences domain, and Apple's app-configuration channel does not deliver there. The app now mirrors the configuration into the shared App Group and tells the extension when it changes, so the keys the engine applies to the connection are enforced too. What replaces the old warning is a timing caveat, which is what an admin actually needs in order to plan a rollout. The hand-off happens only while the app is running: in the foreground a change reaches the tunnel within about 30 seconds or immediately on activation, but iOS suspends a backgrounded app, so a policy pushed — or withdrawn — in that window applies the next time the app is opened. A tunnel brought up by VPN On Demand or the widget therefore runs on the last policy the app saw. tvOS keeps the old behaviour and now says so: the hand-off needs a shared app group, which does not work between the tvOS app and its extension, so only the interface is enforced there. Also corrected: blockInbound, wireguardPort and lazyConnection are no longer listed as having no effect but as having no control to lock, and debugBundleUploadURL moves out of the ignored list, since the engine applies it when a remote job produces a bundle. The app-config template carries the same three keys and the same timing note. * docs: list allowRemoteJobs among the keys iOS enforces without a control The key is enforced on iOS like the other engine-applied ones: a peer whose policy withholds it refuses management-requested jobs. What is not there yet is the lock on the Troubleshoot toggle, which arrives with the iOS client PR that introduces that toggle — so promising it in the table of what the user sees would describe a screen that does not exist. Moved to the group of keys the engine applies with nothing on screen to mark, next to blockInbound, wireguardPort, lazyConnection and debugBundleUploadURL. It moves back to the table once the toggle ships. * docs: sign macOS profiles with CMS, and scope the iOS claims properly Three review findings, all correct. `productsign` signs installer packages, not configuration profiles, and an Apple Developer ID certificate cannot sign a profile at all — Apple's own guidance is that a `.mobileconfig` is a CMS signed-data message. The instruction predates this branch but the commit that fixed the malformed XML comment rewrote it, so it is fixed here rather than carried forward. It was also misleading in a second way: a profile delivered through an MDM is signed by the MDM channel, so a managed rollout has nothing to sign by hand. The step now says that, and gives `security cms -S` for the case where the profile is handed out some other way. "Every key is enforced on iOS" contradicted the list of platform-inapplicable keys three paragraphs below it; it now reads "every key that applies to the platform", and points at that list. The engine-applied group — blockInbound, wireguardPort, lazyConnection, allowRemoteJobs, debugBundleUploadURL — was stated without qualification under a table headed "iOS / tvOS", while the warning just above says the tvOS engine never receives the policy. Marked as iOS, with the tvOS case pointed back at that warning. * docs: group MDM policy keys by job and split delivery into per-platform pages Rewrite /client/mdm-integration as the concept page and key reference: a running example (a three-key baseline), the "pinned switches" model (present means pinned, even as false), and the 23 keys grouped by the job they do, each with its own anchor and the mistake it invites. Correct claims that disagree with the client source (v0.80.0): - disableClientRoutes stops the device using routes (resources, exit nodes); it was described as not routing for others - blockInbound also stops the SSH server and routing; not a kill switch - since v0.75.0 the app hides managed settings, no "(MDM)" tag - a policy change restarts the connection - splitTunnel* have no effect today (Android has no MDM channel yet) - managementURL pins the server, not the account, on NetBird Cloud - the pre-shared key is readable by local users on Windows and macOS Move Windows, macOS and iOS delivery into their own pages under MDM Deployment, add them to the nav, and point inbound links at the new per-key anchors. * docs: fix MDM accuracy points found in review - integer booleans are ignored on macOS (plist decodes as uint64); say so - disableAutostart and disableAdvancedView lock nothing; qualify the lock claim - managementURL: drop the disableProfiles advice, no key pins the account - drop the unverifiable restart duration and a disableAdvancedView claim - macOS page: fix 'never write the file' vs the shell-script channel - Windows page: warn that the sample .reg pins every key - tighten wording * docs: say what disableAdvancedView hides (Peers and Resources tabs) * docs: make clear disableNetworks removes the choice, not the networks * docs: add recommended MDM policies by device role * docs: lazyConnection follows the account setting, on by default since v0.74.0 * docs: drop the open-an-issue line from MDM troubleshooting * docs: make remote jobs optional for every device role * docs: make disableNetworks and disableAdvancedView optional for laptops * docs: rename Recap to TL;DR on the MDM pages * docs: TL;DR on the main MDM page only, drop the lead-in * docs: list MDM Integration first under MDM Deployment in the nav * docs: second review pass on the MDM pages - macOS integer booleans are locked as well as unapplied; say so - the lock-nothing keys are not desktop-only (disableAdvancedView on iOS) - drop Linux from disableAutostart (no MDM channel there) - blockInbound: drop the redundant routed-network clause - encryption intro: Rosenpass permissive does not need to match - troubleshooting: check macOS boolean types, no warning is logged - wording fixes * docs: correct MDM timing and CLI claims from a macOS lab run (v0.80.0) - netbird debug config reads the policy file on each call; the daemon applies a change at its next reload and logs 'MDM policy changed' - netbird up --flag on a connected client ignores its flags; the rejection examples now say login --flag or up on a disconnected client - settings-field locks apply immediately; the disableUpdateSettings, disableProfiles and disableNetworks gates apply at the next reload - the restart on a policy change takes a second or two * docs: MDM results from the Windows and macOS profile labs (v0.80.0) - netbird logout works under every key and deregisters the peer; with managementURL, disableProfiles and disableUpdateSettings pinned, logout plus up --setup-key moves a device to another account on the same URL - a profile-installed macOS policy file is a binary plist, root:wheel 644 - a REG_BINARY (or other unread type) value is not listed as managed - the policy key inherits Authenticated Users read access * docs: tighten four MDM statements to what the labs and source show - no key blocks netbird logout of the active profile (source: only a non-active profile logout is gated, by disableProfiles) - the engine-restart log line appears only while the client is connected - macOS: binary plist is what a configuration profile produces; the shell script writes the same owner and mode - Windows: the observed fact is that the NetBird key inherits Authenticated Users read access, not a statement about the parent key * docs: address CodeRabbit review on the MDM delivery pages - iOS: the app must be managed by the MDM, not necessarily installed by it (Apple supports taking over a user-installed app); same in the iOS app-config template - macOS: Jamf's Application & Custom Settings takes the bare plist, so point Jamf at io.netbird.client.plist (and note the signed .mobileconfig upload route); JumpCloud's MDM Custom Configuration Profile takes a .mobileconfig per JumpCloud's docs, so drop the bare-plist claim and its troubleshooting entry - Windows: ADMXInstall only ingests the template; values are set through Policy/Config/NetBird~Policy~NetBird/<PolicyName>; drop the unverified Registry CSP path * docs: address CodeRabbit's second review of the MDM templates - netbird-macos.sh: managementURL, allowServerSSH and wireguardPort now default to $NULL like every other key; the old defaults pinned them (allowServerSSH=true pinned the SSH server allowed) on any run that did not edit those lines - drop the claim that disableMetricsCollection governs anonymous usage telemetry from the mobileconfig, the bare plist, the script and the ADML help text; the client recognizes the key but nothing reads it * docs: correct the Mosyle path for the macOS MDM profile Mosyle takes the .mobileconfig under Management > Management Profiles > Certificates / Custom Profiles; there is no Custom Settings option with a preference domain (per Orb and SI Prep deployment guides; Mosyle's own docs need a login). Drop Mosyle from the bare-plist template header, and align the mobileconfig header with the Jamf advice on the page. * docs: drop the profiles-command install tip from the macOS template macOS 11 and later cannot install configuration profiles with the profiles command (man profiles, profiles tool 8.0+); point local testing at a double-click and System Settings > General > Device Management, the path the lab used. * docs: make the Windows MDM page Intune-first, with a registry reference section The page now leads with the Intune workflow: import the NetBird ADMX/ADML once, create an Imported Administrative templates profile, assign it to a device group, sync and verify, then the OMA-URI fallback and Intune troubleshooting. Group Policy, .reg files, JumpCloud and the value-type table move to a Registry reference section with its own troubleshooting. New, from Microsoft Learn (Import custom ADMX templates): the current portal paths, en-us ADML only, and that re-importing an updated template fails until the profiles and the old template are deleted. netbird.admx has no namespace dependencies and no combo boxes, so it imports alone. The Intune install page stays separate; both pages now link to each other. Main-page links follow the renamed anchors (#value-types, #intune-troubleshooting). * docs: move the enforce-settings link to the end of the Intune deploy page * docs: group the Windows page's Intune steps under one heading Mirrors the Registry reference section, so the page's table of contents shows the Intune/registry split. Heading texts and anchors are unchanged. * docs: rename the first MDM key group to Set the server and startup The old heading named only managementURL; the group also holds disableAutoConnect and disableAutostart. * docs: add a use case to the Lock the client app section What a developer on a locked Acme laptop sees (app tabs, the two CLI errors, what still works), plus the finance team's disableNetworks and Auto Apply exit node variant. Every behaviour is from the macOS and Windows labs (v0.80.0). * docs: replace the Lock the client app use case with a plain goals table Goal, setting, and what users can still do, written for a junior admin. disableProfiles row says plainly that signing out and into another account still works (Windows lab W12). * docs: OMA-URI payloads: <disabled/> pins an on/off setting off The ADMX's on/off policies write enabledValue 1 and disabledValue 0, so <enabled/> can only pin a setting on; document <disabled/> for off, the String data type, and that un-pinning means Not configured (check the device with reg query, since removing an OMA-URI may not clear it). * docs: add What you can achieve tables to every MDM key section Same goal / setting / what-to-know format as Lock the client app, for server and startup, device exposure, encryption, support and monitoring, and connection tuning; Lock's table now names values too. Every line restates a claim already verified in the labs or source. * docs: reorder the MDM page: goals first, key reference after - What you can achieve (the six goal tables) comes first, then Recommended policies, How the client applies a policy, and the Policy keys reference; goal-table keys link down to their reference entries - reference groups get noun names (Server and startup keys, ...) so no two headings share an anchor - the Acme running example is gone; its three keys become The laptop baseline under Recommended policies, which the Windows, macOS and iOS pages now link to as their example - a one-line pin rule opens the goals, since the explanation now follows * docs: laptop baseline goes to the user-devices group, not just laptops * docs: rename the laptop baseline to the user device baseline It applies to every user device (and the iOS page uses it), so the Recommended policies column becomes User devices, the anchor becomes #the-user-device-baseline, and the three platform pages follow. --------- Co-authored-by: riccardom <riccardomanfrin@gmail.com>
This commit is contained in:
@@ -14,6 +14,8 @@ This division of security responsibilities creates a comprehensive zero trust im
|
||||
|
||||
In this hands-on tutorial, you'll learn how to deploy NetBird with Intune to grant tailored access permissions for different teams.
|
||||
|
||||
This page installs the NetBird client. To enforce its settings once it is installed, such as pinning the management server or making settings read-only, follow [Enforce NetBird Settings on Windows](/manage/peers/mdm-deployment/windows-mdm-policy), which uses an Intune configuration profile.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before beginning this tutorial, ensure you have the following prerequisites in place:
|
||||
@@ -219,4 +221,8 @@ To verify that NetBird was added to Intune, navigate to `Home > Apps | Windows`
|
||||
|
||||
While each platform has slightly different configuration options, adding NetBird and assigning it to groups follows the same pattern across Intune. For more information, refer to [Intune app management](https://learn.microsoft.com/en-us/intune/intune-service/apps/app-management).
|
||||
|
||||
With NetBird successfully deployed through Intune, your organization has the foundation for implementing a comprehensive zero trust access model that verifies user identity and device compliance before granting network access.
|
||||
With NetBird successfully deployed through Intune, your organization has the foundation for implementing a comprehensive zero trust access model that verifies user identity and device compliance before granting network access.
|
||||
|
||||
## Next: enforce the client's settings
|
||||
|
||||
With the client installed, use an Intune configuration profile to pin its settings, such as the management server, and to stop users changing them: see [Enforce NetBird Settings on Windows](/manage/peers/mdm-deployment/windows-mdm-policy).
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Note, Warning } from "@/components/mdx";
|
||||
|
||||
export const description =
|
||||
"Deliver NetBird MDM policy to iOS, iPadOS, and tvOS devices with Managed App Configuration: the payload, where to put it in Intune, Jamf Pro, and other MDMs, when a change reaches the tunnel, and what each key does in the app.";
|
||||
|
||||
# Enforce NetBird Settings on iOS
|
||||
|
||||
On iOS there is no file or registry for policy. Apple's channel for configuring a managed app is **Managed App Configuration**: your MDM sends a dictionary along with the app, and iOS hands it to that app only. The NetBird app reads it from its own preferences, so the payload must target the NetBird app's bundle id: `io.netbird.app` on iOS and iPadOS, `io.netbird.app.tv` on tvOS.
|
||||
|
||||
What each key does, and how the client applies and locks a policy, is on the [MDM Integration](/client/mdm-integration) page. Read its [How the client applies a policy](/client/mdm-integration#how-the-client-applies-a-policy) section first if you have not.
|
||||
|
||||
The examples use [the user device baseline](/client/mdm-integration#the-user-device-baseline): a self-hosted server at `https://netbird.example.com:443`, read-only settings, and no extra profiles.
|
||||
|
||||
<Note>
|
||||
**The app must be managed by the MDM that sends the configuration.** It does not have to be installed by it: an MDM can take over management of a copy the user installed from the App Store, and on an unsupervised device the user has to accept that change. Until the app is managed it receives no app configuration, and NetBird runs with no policy on that device.
|
||||
</Note>
|
||||
|
||||
## Push the payload
|
||||
|
||||
The payload is a plain property-list dictionary, with the same key names as on desktop. The user device baseline is:
|
||||
|
||||
```xml
|
||||
<dict>
|
||||
<key>managementURL</key>
|
||||
<string>https://netbird.example.com:443</string>
|
||||
<key>disableUpdateSettings</key>
|
||||
<true/>
|
||||
<key>disableProfiles</key>
|
||||
<true/>
|
||||
</dict>
|
||||
```
|
||||
|
||||
Start from <a href="/docs-static/files/netbird-ios-appconfig.plist" download>netbird-ios-appconfig.plist</a> and delete the keys you do not want to pin: a key that is present is pinned, even when its value is `false`. Then add it to the NetBird app's assignment in your MDM:
|
||||
|
||||
- **Microsoft Intune**: **Apps → App configuration policies → Add → Managed devices**, platform **iOS/iPadOS**, pick the NetBird app, then set **Configuration settings format** to **Enter XML data** and paste the dictionary.
|
||||
- **Jamf Pro**: **Devices → Mobile Device Apps → NetBird → App Configuration**, and paste the dictionary.
|
||||
- **Kandji**, **Mosyle**, **Workspace ONE**, **JumpCloud**: the same field exists on the managed-app assignment, usually labelled *App Configuration* or *Application Configuration*.
|
||||
|
||||
Booleans can be written as `<true/>` and `<false/>`, or as `<integer>1</integer>` and `<integer>0</integer>`. Integers and strings behave as on desktop.
|
||||
|
||||
## When a policy takes effect
|
||||
|
||||
Every key that applies to iOS is enforced: the keys that reshape the app, and the keys the client applies to the connection itself. When a change lands depends on one detail of how iOS works.
|
||||
|
||||
iOS delivers the configuration to the NetBird app. The tunnel, though, runs in a Network Extension: a separate process the system starts when the tunnel comes up and stops when it goes down, and which Apple's app-configuration channel does not reach. The app therefore passes the configuration on to the extension whenever the app is running: when it becomes active, when a settings screen appears, and on a timer about every 30 seconds. When the policy has changed, the tunnel restarts on its own and the user is told their IT policy was applied.
|
||||
|
||||
<Note>
|
||||
**A policy lands while the app is open.** With NetBird in the foreground, a change pushed from your MDM reaches the tunnel within about 30 seconds, or at once when the user switches back to the app. Nothing has to be restarted by hand.
|
||||
|
||||
**While the app is closed or in the background, iOS suspends it**, and a policy pushed or withdrawn in that time reaches the tunnel only the next time the app is opened. This matters most with VPN On Demand or the widget, where the tunnel can come up without the app ever appearing: it then runs on the last policy the app saw. Plan rollouts accordingly, and treat "applied" as "applied once the user next opens the app".
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
**On tvOS, only the app is enforced, not the tunnel.** The hand-off described above relies on a shared app group, which does not work between the tvOS app and its extension, so the tvOS tunnel runs without the policy. Keys that lock or hide controls behave as described below; the keys the client applies to the connection (`managementURL`, `preSharedKey`, `rosenpassEnabled`, `rosenpassPermissive`, `blockInbound`, `wireguardPort`, `lazyConnection`) do not reach the tunnel on tvOS yet.
|
||||
</Warning>
|
||||
|
||||
## What each key does in the app
|
||||
|
||||
| Key | Effect in the iOS and tvOS app |
|
||||
| --- | --- |
|
||||
| `managementURL` | Hides **Settings → Connection** and the server step of onboarding. The profile-creation sheet shows and uses the pinned URL. |
|
||||
| `preSharedKey` | The key row reads *Configured* and is locked: no Save, no Remove. The value itself never reaches the app's interface. |
|
||||
| `rosenpassEnabled`, `rosenpassPermissive` | Locks its own switch and shows the pinned value. |
|
||||
| `disableClientRoutes` | Hides the exit-node selector. The resource list explains why, instead of listing resources. |
|
||||
| `disableAutoConnect` | VPN On Demand becomes read-only. |
|
||||
| `disableProfiles` | Hides the Profiles section: no creating, switching, or removing profiles. |
|
||||
| `disableNetworks` | Removes the Resources tab. |
|
||||
| `disableAdvancedView` | Hides Advanced (on tvOS, the whole section). |
|
||||
| `disableUpdateSettings` | Read-only mode: nothing is hidden, and every configuration control is locked. |
|
||||
|
||||
A second group of keys has no control to lock, because the client applies them straight to the connection: `blockInbound`, `wireguardPort`, `lazyConnection`, `allowRemoteJobs`, and `debugBundleUploadURL` (when a remote job produces a bundle). On iOS they are enforced all the same, with nothing on screen to mark: a device whose policy sets `allowRemoteJobs: false`, for example, refuses remote jobs. On tvOS none of them reach the tunnel, for the reason in the warning above.
|
||||
|
||||
The remaining keys do not apply to iOS and are ignored, so they are safe in a payload shared with desktop devices: `allowServerSSH` (there is no SSH server on iOS), `disableServerRoutes` (an iOS device does not route for other peers), `disableAutostart` (desktop app only), `disableMetricsCollection`, `enableLocalMetrics` and `localMetricsAddress` (the local endpoint is not reachable on iOS), and `splitTunnelMode` and `splitTunnelApps`.
|
||||
|
||||
## Verifying on a device
|
||||
|
||||
There is no CLI on iOS. A pinned setting shows a lock and a **Managed by your organization** note in the app, and a gated section disappears altogether. For the user device baseline, the Profiles section is gone and every configuration control is locked.
|
||||
|
||||
That confirms the app received the policy. To confirm it reached the *tunnel*, change the policy while the tunnel is connected and bring NetBird to the foreground: the tunnel restarts and the device shows "NetBird configuration was updated by your IT policy". That notice comes from the extension, so seeing it means the tunnel applied the new policy.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Nothing is locked in the app.**
|
||||
The app did not receive the configuration. Check that NetBird is a managed app on the device (installed by your MDM, or taken over by it), that the app-configuration policy is assigned to the same device group as the app, and that it targets the bundle id `io.netbird.app` (`io.netbird.app.tv` on tvOS).
|
||||
|
||||
**The app shows the policy, but the tunnel still behaves as before.**
|
||||
The app passes the policy to the tunnel only while it is running. Open NetBird and leave it in the foreground for half a minute; the tunnel restarts and reports that the policy was applied. On tvOS the tunnel does not receive the policy at all; see [When a policy takes effect](#when-a-policy-takes-effect).
|
||||
|
||||
For problems that look the same on every platform, see [Troubleshooting](/client/mdm-integration#troubleshooting) on the MDM Integration page.
|
||||
|
||||
## Recap
|
||||
|
||||
- iOS delivers the policy as Managed App Configuration to the managed NetBird app, bundle id `io.netbird.app` (tvOS: `io.netbird.app.tv`).
|
||||
- The user device baseline is the same three keys as on desktop: `managementURL`, `disableUpdateSettings`, and `disableProfiles`.
|
||||
- A change reaches the tunnel while the app is open, within about 30 seconds; on tvOS it reaches the app only.
|
||||
- Confirm in the app: pinned settings show **Managed by your organization**.
|
||||
@@ -0,0 +1,127 @@
|
||||
import { Note, Warning } from "@/components/mdx";
|
||||
|
||||
export const description =
|
||||
"Deliver NetBird MDM policy to macOS devices: a configuration profile for the io.netbird.client preference domain, with steps for Jamf Pro, Kandji, Mosyle, Intune, Workspace ONE, and JumpCloud, and how to confirm it arrived.";
|
||||
|
||||
# Enforce NetBird Settings on macOS
|
||||
|
||||
On macOS, the NetBird client reads its MDM policy from `/Library/Managed Preferences/io.netbird.client.plist`. Normally you do not write that file yourself: macOS writes it when your MDM installs a configuration profile with managed preferences for the preference domain (bundle id) `io.netbird.client`. This page shows how to build that profile, deliver it with the common MDMs, and confirm it arrived.
|
||||
|
||||
What each key does, and how the client applies and locks a policy, is on the [MDM Integration](/client/mdm-integration) page. Read its [How the client applies a policy](/client/mdm-integration#how-the-client-applies-a-policy) section first if you have not.
|
||||
|
||||
The examples use [the user device baseline](/client/mdm-integration#the-user-device-baseline): a self-hosted server at `https://netbird.example.com:443`, read-only settings, and no extra profiles. As managed preferences, the whole policy is:
|
||||
|
||||
```xml
|
||||
<key>managementURL</key>
|
||||
<string>https://netbird.example.com:443</string>
|
||||
<key>disableUpdateSettings</key>
|
||||
<true/>
|
||||
<key>disableProfiles</key>
|
||||
<true/>
|
||||
```
|
||||
|
||||
<Warning>
|
||||
**macOS clears `/Library/Managed Preferences/` at every boot on a Mac that is not enrolled in an MDM.** Writing the file by hand, with `defaults write` or a script, works for a quick test, but the policy is gone after the next reboot. Use a configuration profile delivered by an MDM for anything beyond a test.
|
||||
</Warning>
|
||||
|
||||
## Templates
|
||||
|
||||
Download the template that matches your MDM:
|
||||
|
||||
- <a href="/docs-static/files/netbird-macos.mobileconfig" download>netbird-macos.mobileconfig</a>: a complete configuration profile. Use it with Kandji, Mosyle, Intune, Workspace ONE, JumpCloud, and Apple Configurator.
|
||||
- <a href="/docs-static/files/io.netbird.client.plist" download>io.netbird.client.plist</a>: the bare managed-preferences dictionary, without the profile wrapper. Use it with Jamf Pro's Application & Custom Settings payload.
|
||||
- <a href="/docs-static/files/netbird-macos.sh" download>netbird-macos.sh</a>: a script that writes the policy file directly, for JumpCloud fleets that are not MDM-enrolled.
|
||||
|
||||
Each template lists every key. Delete the keys you do not want to pin: a key that is present is pinned, even when its value is `false`.
|
||||
|
||||
Write booleans as `<true/>` or `<false/>`. On macOS, a boolean written as `<integer>1</integer>` is listed as managed and locked, but never applied, so the setting is frozen at whatever the Mac had.
|
||||
|
||||
## Build the configuration profile
|
||||
|
||||
1. Open `netbird-macos.mobileconfig` in a text editor, or in a profile editor such as [iMazing Profile Editor](https://imazing.com/profile-editor) or [ProfileCreator](https://github.com/ProfileCreator/ProfileCreator).
|
||||
2. Inside the `mcx_preference_settings` dictionary, keep only the keys you want to pin, with your values. For the user device baseline, that is the three keys shown at the top of this page. Keep `io.netbird.client` as the preference domain.
|
||||
3. Replace each placeholder `PayloadUUID` with a freshly generated UUID (run `uuidgen`), so every deployment has unique identifiers.
|
||||
|
||||
Profiles delivered through an MDM are signed by the MDM, so there is nothing to sign by hand for a managed rollout. A profile you hand out some other way, with Apple Configurator or as a file a user double-clicks, installs unsigned, and recent macOS releases ask the user for an extra confirmation. To avoid that, sign the profile as a CMS message:
|
||||
|
||||
```bash
|
||||
security cms -S -N "<signing identity>" -i netbird-macos.mobileconfig -o signed.mobileconfig
|
||||
```
|
||||
|
||||
Use an identity the target Macs already trust. Configuration profiles are **not** signed with `productsign`, which is for installer packages, nor with an Apple Developer ID certificate.
|
||||
|
||||
## Deliver it with your MDM
|
||||
|
||||
- **Jamf Pro**: **Computers → Configuration Profiles → New → Application & Custom Settings → External Applications → Upload File (Plist file)**, with the preference domain `io.netbird.client`, and upload the edited `io.netbird.client.plist`. Jamf can also take the whole `.mobileconfig` through **Computers → Configuration Profiles → Upload**, but it may drop payload keys it does not recognize from an unsigned profile, so sign the profile first if you use that route.
|
||||
- **Kandji**: add a **Custom Profile** library item and upload the `.mobileconfig`.
|
||||
- **Mosyle**: **Management → Management Profiles → Certificates / Custom Profiles → Add new profile**, and upload the `.mobileconfig`.
|
||||
- **Microsoft Intune**: **Devices → Configuration → Create profile → macOS → Templates → Custom**, and upload the `.mobileconfig`.
|
||||
- **Workspace ONE** and other MDMs: upload the `.mobileconfig` as a custom configuration profile and scope it to the target device group.
|
||||
- **Apple Configurator 2**, for testing on a connected Mac without an MDM: drag the `.mobileconfig` onto the device and install it.
|
||||
|
||||
### JumpCloud
|
||||
|
||||
JumpCloud can deliver the policy two ways. Use the first if your Macs are MDM-enrolled with JumpCloud.
|
||||
|
||||
#### MDM Custom Configuration Profile (MDM-enrolled Macs)
|
||||
|
||||
1. In the JumpCloud admin console, open **Policy Management → Policies → +** and choose the **Mac** platform.
|
||||
2. Pick the **MDM Custom Configuration Profile** policy template.
|
||||
3. Under **Settings**, upload your edited `netbird-macos.mobileconfig` (see [Build the configuration profile](#build-the-configuration-profile)).
|
||||
4. Bind the policy to the target device group and save.
|
||||
|
||||
JumpCloud delivers the profile through MDM. Removing the policy in JumpCloud removes the file at the next sync, which unpins the settings on the client.
|
||||
|
||||
#### Shell command (Macs not enrolled in MDM)
|
||||
|
||||
For JumpCloud-managed Macs that are not MDM-enrolled, use <a href="/docs-static/files/netbird-macos.sh" download>netbird-macos.sh</a>:
|
||||
|
||||
1. Edit the `### POLICY VALUES ###` block at the top of the script: set the keys you want to pin, and leave the rest at `$NULL`.
|
||||
2. In the JumpCloud admin console, go to **Device Management → Commands → +**. Set **Type** to **Mac, Shell** and **Run as** to **root**.
|
||||
3. Paste the edited script into the command body.
|
||||
4. Bind the command to the target device group and run it.
|
||||
|
||||
The script writes `/Library/Managed Preferences/io.netbird.client.plist`, owned by `root:wheel` with mode `644`, and restarts the NetBird daemon so the policy applies at once. On a Mac that is not MDM-enrolled, macOS deletes the file at the next reboot, so run the command again after each reboot, or enroll the Macs and use the configuration profile.
|
||||
|
||||
<Note>
|
||||
**Every user on the Mac can read the policy file.** From a configuration profile, macOS writes it as a binary plist owned by `root:wheel` with mode `644`, and the shell script above uses the same owner and mode. It is readable by all users, so a `preSharedKey` or `debugBundleUploadURL` in it is visible to anyone who can sign in. Only root can change it. The client refuses to read a policy file that any user can write to, and then enforces no policy at all, so never loosen the file's permissions.
|
||||
</Note>
|
||||
|
||||
## Verify
|
||||
|
||||
On a target Mac, check that macOS wrote the policy file:
|
||||
|
||||
```bash
|
||||
sudo defaults read "/Library/Managed Preferences/io.netbird.client"
|
||||
```
|
||||
|
||||
The output should list the keys from your profile. Then check what the client is enforcing:
|
||||
|
||||
```bash
|
||||
netbird debug config
|
||||
```
|
||||
|
||||
The `mDMManagedFields` array in the output lists every key in the policy the client reads. For the user device baseline, it contains `disableProfiles`, `disableUpdateSettings`, and `managementURL`. The client log at `/var/log/netbird/client.log` has an `MDM enrolled with N managed key(s): [...]` line on every reload, and an `MDM policy changed: added=[...]` line once the daemon has applied a change, within a minute. See [Verifying enforcement](/client/mdm-integration#verifying-enforcement) for more.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**The policy file does not exist.**
|
||||
The profile was not installed, or it targets the wrong preference domain. On the Mac, open **System Settings → General → Device Management** and confirm the profile is listed, then confirm the domain in the profile is exactly `io.netbird.client`.
|
||||
|
||||
**The policy file disappears after a reboot.**
|
||||
The Mac is not MDM-enrolled, so macOS clears `/Library/Managed Preferences/` at boot. Enroll it and deliver the policy as a configuration profile.
|
||||
|
||||
**The file exists, but `mDMManagedFields` is empty.**
|
||||
Check the file's permissions with `ls -l "/Library/Managed Preferences/io.netbird.client.plist"`. If any user can write to it (a `w` in the last three permission characters), the client ignores the whole policy, and with default logging it says nothing about it. Reset the permissions with `sudo chown root:wheel` and `sudo chmod 644` on the file. If the permissions are fine, look in the client log for `MDM ignoring unknown plist key`: a key name does not match any key in the [reference](/client/mdm-integration#policy-keys-reference).
|
||||
|
||||
**A key is listed in `mDMManagedFields`, but the setting did not change.**
|
||||
Check the value's type. A boolean must be `<true/>` or `<false/>`; written as an `<integer>`, it is listed as managed and locked, but never applied. The client logs no warning for it.
|
||||
|
||||
For problems that look the same on every platform, see [Troubleshooting](/client/mdm-integration#troubleshooting) on the MDM Integration page.
|
||||
|
||||
## Recap
|
||||
|
||||
- The client reads `/Library/Managed Preferences/io.netbird.client.plist`, which macOS writes from a configuration profile for `io.netbird.client`.
|
||||
- The user device baseline is three keys: `managementURL`, `disableUpdateSettings`, and `disableProfiles`.
|
||||
- Upload `netbird-macos.mobileconfig` to most MDMs, JumpCloud included; Jamf Pro's Application & Custom Settings takes the bare `io.netbird.client.plist`.
|
||||
- Confirm with `sudo defaults read`, then `netbird debug config`.
|
||||
@@ -0,0 +1,171 @@
|
||||
import { Note, Warning } from "@/components/mdx";
|
||||
|
||||
export const description =
|
||||
"Enforce NetBird client settings on Windows with Microsoft Intune: import the NetBird administrative templates, build and assign a configuration profile, and verify it. Plus a registry reference for Group Policy, JumpCloud, and .reg files.";
|
||||
|
||||
# Enforce NetBird Settings on Windows
|
||||
|
||||
On Windows, you enforce NetBird settings with Microsoft Intune: import NetBird's administrative templates once, build a configuration profile from them, and assign it to your devices. The client then applies the settings and locks them. Behind the scenes, the profile writes values to one registry key, `HKLM\Software\Policies\NetBird`, which is what the client reads. The [registry reference](#registry-reference) at the end of this page covers that key directly, for Group Policy, JumpCloud, or a `.reg` file.
|
||||
|
||||
This page enforces settings on a client that is already installed. To install the client with Intune, follow [Deploying NetBird with Intune](/manage/peers/mdm-deployment/intune-netbird-integration) first. What each setting does, and how the client applies and locks a policy, is on the [MDM Integration](/client/mdm-integration) page.
|
||||
|
||||
The examples use [the user device baseline](/client/mdm-integration#the-user-device-baseline): a self-hosted server at `https://netbird.example.com:443`, read-only settings, and no extra profiles. In Intune that is three policies: **Management URL**, **Disable update settings**, and **Disable profiles**.
|
||||
|
||||
## Before you start
|
||||
|
||||
- An Intune admin account with at least the **Policy and Profile Manager** role.
|
||||
- Windows devices enrolled in Intune, with the NetBird client installed, in a device group you can assign to.
|
||||
- The NetBird templates: <a href="/docs-static/files/netbird.admx" download>netbird.admx</a> and <a href="/docs-static/files/netbird.adml" download>netbird.adml</a>. They cover every setting, have no dependency on other templates, and stay within Intune's limits for imported templates.
|
||||
|
||||
## Enforce settings with Intune
|
||||
|
||||
### Step 1: Import the NetBird templates
|
||||
|
||||
You do this once per tenant.
|
||||
|
||||
1. In the Intune admin center, go to **Devices → Manage devices → Configuration**, open the **Import ADMX** tab, and select **Import**.
|
||||
2. Upload `netbird.admx` as the ADMX file and `netbird.adml` as the ADML file for the default language (`en-us`, the only language Intune accepts).
|
||||
3. Select **Next**, then **Create**.
|
||||
4. Select **Refresh** until the template's status is **Available**.
|
||||
|
||||
<Note>
|
||||
**Updating the templates later.** Intune refuses to import a template whose settings are already imported. When NetBird ships updated templates, for example with new settings, delete the configuration profiles that use the NetBird template, delete the old template on the **Import ADMX** tab, and then import the new files. Note your profile settings before you delete them.
|
||||
</Note>
|
||||
|
||||
### Step 2: Create the configuration profile
|
||||
|
||||
1. Go to **Devices → Manage devices → Configuration → Create → New policy**.
|
||||
2. Set **Platform** to **Windows 10 and later** and **Profile type** to **Templates**, then select **Imported Administrative templates (Preview)** and **Create**.
|
||||
3. Give the profile a name you can find later, such as `NetBird: user device baseline`.
|
||||
4. Under **Configuration settings**, open **NetBird**. Each policy is named after its setting in plain words. For the user device baseline:
|
||||
- **Management URL**: **Enabled**, value `https://netbird.example.com:443`.
|
||||
- **Disable update settings**: **Enabled**.
|
||||
- **Disable profiles**: **Enabled**.
|
||||
|
||||
Leave every other policy **Not configured**. A policy set to **Disabled** is not the same as **Not configured**: it pins the setting to `false`, out of the user's reach. See [How the client applies a policy](/client/mdm-integration#how-the-client-applies-a-policy).
|
||||
5. Under **Assignments**, assign the profile to a **device group**. NetBird's policies are machine settings, so a device group is what you want. To build the profile for each device role, use [Recommended policies](/client/mdm-integration#recommended-policies), and keep routing peers out of any group that gets **Block inbound** or **Disable server routes**.
|
||||
6. Select **Create**.
|
||||
|
||||
### Step 3: Sync and verify
|
||||
|
||||
Devices pick up the profile at their next Intune check-in. To speed up a test device, open **Settings → Accounts → Access work or school**, select the work account, select **Info**, and then **Sync**. The NetBird client applies the policy within a minute of it arriving, and restarts its connection to do so: expect a brief interruption.
|
||||
|
||||
In the Intune admin center, open the profile and check its device and user check-in status. On the device itself:
|
||||
|
||||
```
|
||||
reg query HKLM\Software\Policies\NetBird
|
||||
netbird debug config
|
||||
```
|
||||
|
||||
`reg query` shows the values Intune wrote. In `netbird debug config`, the `mDMManagedFields` array lists every setting in the policy the client reads; for the user device baseline it contains `disableProfiles`, `disableUpdateSettings`, and `managementURL`. The client log at `C:\ProgramData\Netbird\client.log` has an `MDM policy changed: added=[...]` line once the client has applied the change. See [Verifying enforcement](/client/mdm-integration#verifying-enforcement) for more.
|
||||
|
||||
### If you cannot import templates: custom OMA-URI
|
||||
|
||||
Imported templates are the simpler path; prefer them. Without them, a custom OMA-URI profile (**Templates → Custom**) takes two kinds of setting, following Microsoft's [ADMX-backed policy ingestion](https://learn.microsoft.com/en-us/windows/client-management/win32-and-centennial-app-policy-configuration):
|
||||
|
||||
1. **Ingest the template**: OMA-URI `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/NetBird/Policy/NetBirdAdmx`, data type **String**, value: the full contents of `netbird.admx`. This only makes the policies known to the device; it sets nothing.
|
||||
2. **Set each policy**: OMA-URI `./Device/Vendor/MSFT/Policy/Config/NetBird~Policy~NetBird/<PolicyName>`, where `<PolicyName>` is the policy's `name` in `netbird.admx`, with data type **String**. The value depends on what you want to pin:
|
||||
- **On, or a value**: `<enabled/>`, plus a `<data id="..." value="..."/>` element for a policy that carries a value, with the element `id` from the same policy in `netbird.admx`.
|
||||
- **Off**: `<disabled/>`. For the on/off policies the template writes `0`, which pins the setting off. `<enabled/>` always writes `1`, so never use it to turn a setting off.
|
||||
|
||||
For the user device baseline's server, the **Management URL** policy is `.../NetBird~Policy~NetBird/ManagementURL` with the value `<enabled/><data id="ManagementURL_Text" value="https://netbird.example.com:443"/>`.
|
||||
|
||||
To stop pinning a setting, it has to go back to **Not configured**, not `<disabled/>`. Removing an OMA-URI from a custom profile is not guaranteed to clear the value on the device, so check with `reg query HKLM\Software\Policies\NetBird` afterwards.
|
||||
|
||||
The URIs above follow Microsoft's naming rules for this template; they have not been tested in an Intune tenant.
|
||||
|
||||
### Intune troubleshooting
|
||||
|
||||
**The template import fails.**
|
||||
If the error says the settings already exist, an earlier version of the NetBird template is imported: see **Updating the templates later** above. Otherwise, check that you uploaded `netbird.adml` with `netbird.admx`, as the `en-us` language file.
|
||||
|
||||
**The profile shows an error or never reaches the device.**
|
||||
Check the profile's per-device status in the admin center, and that the device is in the assigned device group. On the device, trigger a sync from **Settings → Accounts → Access work or school → Info → Sync**, then run `reg query HKLM\Software\Policies\NetBird`. If the key is empty, the profile has not been applied yet.
|
||||
|
||||
**The values are in the registry, but the setting did not change.**
|
||||
The client applies a change at its next reload, within a minute. If `mDMManagedFields` still does not list the setting, or lists it without the setting changing, see [Registry troubleshooting](#registry-troubleshooting).
|
||||
|
||||
For problems that look the same on every platform, see [Troubleshooting](/client/mdm-integration#troubleshooting) on the MDM Integration page.
|
||||
|
||||
## Registry reference
|
||||
|
||||
Whatever writes it, the client reads its policy from `HKLM\Software\Policies\NetBird`: an Intune profile, a Group Policy object, a script, or `reg import` all end in the same key. This section is for working with that key directly, and for checking what Intune wrote.
|
||||
|
||||
### Value types
|
||||
|
||||
Each setting needs a value of the right registry type. Value names are matched without regard to case.
|
||||
|
||||
| Registry type | Value names |
|
||||
| --- | --- |
|
||||
| `REG_SZ` (string) | `ManagementURL`, `PreSharedKey`, `DebugBundleUploadURL`, `LocalMetricsAddress`, `SplitTunnelMode`, `SplitTunnelApps` |
|
||||
| `REG_DWORD`, `0` or `1` (boolean) | `AllowRemoteJobs`, `AllowServerSSH`, `BlockInbound`, `DisableAdvancedView`, `DisableAutoConnect`, `DisableAutostart`, `DisableClientRoutes`, `DisableMetricsCollection`, `DisableNetworks`, `DisableProfiles`, `DisableServerRoutes`, `DisableUpdateSettings`, `EnableLocalMetrics`, `LazyConnection`, `RosenpassEnabled`, `RosenpassPermissive` |
|
||||
| `REG_DWORD` (integer) | `WireguardPort`, for example `0x0000ca6c` for `51820` |
|
||||
|
||||
A boolean can also be a `REG_SZ` holding `true`/`false`, `1`/`0`, `yes`/`no`, or `on`/`off`. A string setting stored with any type other than `REG_SZ` or `REG_EXPAND_SZ` is ignored: a `ManagementURL` stored as a `REG_DWORD`, for example, has no effect. The client reads `REG_SZ`, `REG_EXPAND_SZ`, `REG_DWORD`, `REG_QWORD`, and `REG_MULTI_SZ` values. Any other type, such as `REG_BINARY`, is skipped with a warning in its log and is not listed in `mDMManagedFields`.
|
||||
|
||||
<Note>
|
||||
**Standard users can read these values.** By default, the NetBird policy key inherits read access for Authenticated Users, so a `PreSharedKey` or `DebugBundleUploadURL` stored there is visible to them. Only administrators can change the values. An administrator on the device can always edit or delete the key, so give users standard accounts.
|
||||
</Note>
|
||||
|
||||
The user device baseline as raw registry values:
|
||||
|
||||
```
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\Policies\NetBird]
|
||||
"ManagementURL"="https://netbird.example.com:443"
|
||||
"DisableUpdateSettings"=dword:00000001
|
||||
"DisableProfiles"=dword:00000001
|
||||
```
|
||||
|
||||
### Group Policy
|
||||
|
||||
For domain-joined devices, follow [Deploying NetBird with Group Policy (GPO)](/manage/peers/mdm-deployment/windows-gpo-deployment). It walks through the Central Store, creating the policy GPO, installing the MSI silently, and scoping, end to end. The same `netbird.admx` and `netbird.adml` templates appear under **Computer Configuration → Administrative Templates → NetBird**.
|
||||
|
||||
To test the templates on a single machine with the local Group Policy editor:
|
||||
|
||||
1. Copy `netbird.admx` to `C:\Windows\PolicyDefinitions\` and `netbird.adml` to `C:\Windows\PolicyDefinitions\en-US\`.
|
||||
2. Open `gpedit.msc` and go to **Computer Configuration → Administrative Templates → NetBird**.
|
||||
3. Open a policy, such as **Management URL**, set it to **Enabled**, enter the value, and click **OK**.
|
||||
4. Run `gpupdate /force`.
|
||||
|
||||
### A `.reg` file
|
||||
|
||||
For a device without an MDM, or a quick test, carry the whole policy in one `.reg` file, such as the user device baseline above, and apply it from an elevated prompt with `reg import netbird-policy.reg`. To build one from a reference machine that already has the policy you want, export the key with `reg export "HKLM\Software\Policies\NetBird" netbird-policy.reg /y`.
|
||||
|
||||
<a href="/docs-static/files/netbird-policy.reg" download>netbird-policy.reg</a> is a sample that sets every setting, including `PreSharedKey` and `DisableClientRoutes`, which cut a laptop off from most of the network. Delete every line you do not mean to pin before you use it.
|
||||
|
||||
`reg import` adds and overwrites values, but never removes them. To take a setting out of the policy, delete its value with `reg delete "HKLM\Software\Policies\NetBird" /v <ValueName> /f`.
|
||||
|
||||
### JumpCloud
|
||||
|
||||
NetBird ships a companion script for JumpCloud, <a href="/docs-static/files/netbird-policy.reg.ps1" download>netbird-policy.reg.ps1</a>, that applies a `.reg` file as the complete policy for the device.
|
||||
|
||||
1. In the JumpCloud admin console, go to **Device Management → Commands → +**.
|
||||
2. Set **Type** to **Windows PowerShell** and **Run as** to **SYSTEM**.
|
||||
3. Paste `netbird-policy.reg.ps1` into the command body, unchanged.
|
||||
4. Attach your `.reg` file to the same command. JumpCloud copies attached files into the command's working directory before it runs the script.
|
||||
5. Bind the command to the target device group and run it.
|
||||
|
||||
The script deletes the existing `HKLM\Software\Policies\NetBird` key before it imports the `.reg` file, so the file is the **complete** policy for the device: any setting it does not contain is no longer pinned. To remove the whole policy, attach a `.reg` file that contains only the header line.
|
||||
|
||||
### Registry troubleshooting
|
||||
|
||||
**`reg query` shows no values.**
|
||||
Nothing wrote them. For Group Policy, run `gpresult /h report.html` and look for errors on the NetBird GPO. For Intune, see [Intune troubleshooting](#intune-troubleshooting).
|
||||
|
||||
**The values are in the registry, but `mDMManagedFields` does not list them.**
|
||||
Look for `MDM ignoring unknown registry value` in the client log: the value name does not match a setting. Then look for `MDM ignoring unsupported registry value type`: the value has a registry type the client does not read.
|
||||
|
||||
**A setting is listed in `mDMManagedFields`, but it did not change.**
|
||||
The value has the wrong type for its setting, such as a `ManagementURL` stored as a `REG_DWORD`. Check it against [Value types](#value-types).
|
||||
|
||||
**A setting stays pinned after you removed it from a `.reg` file.**
|
||||
`reg import` does not delete values. Delete the value with `reg delete`, or use the [JumpCloud](#jump-cloud) script, which replaces the whole key.
|
||||
|
||||
## Recap
|
||||
|
||||
- Import `netbird.admx` and `netbird.adml` into Intune once, build a configuration profile from **Imported Administrative templates**, and assign it to a device group.
|
||||
- The user device baseline enables three policies: **Management URL**, **Disable update settings**, and **Disable profiles**. Everything else stays **Not configured**.
|
||||
- Confirm in Intune, then on the device with `reg query` and `netbird debug config`.
|
||||
- Without Intune, the same settings are registry values under `HKLM\Software\Policies\NetBird`, written by Group Policy, JumpCloud, or a `.reg` file.
|
||||
@@ -77,7 +77,7 @@ On the machine you want to access via SSH, enable the NetBird SSH server.
|
||||
On a machine where you do not have those rights, which is the normal case for a
|
||||
managed workstation, you cannot enable the SSH server yourself: an administrator
|
||||
has to run the command. For the SSH server itself there is also
|
||||
[`allowServerSSH`](/client/mdm-integration#policy-keys-reference), which the client
|
||||
[`allowServerSSH`](/client/mdm-integration#allowServerSSH), which the client
|
||||
applies from MDM policy and so needs nothing from you; root login and SSH
|
||||
authentication have no policy key and must be set on the machine. A switch already in its safe
|
||||
state stays operable: you can turn the SSH server off, turn root login off, or
|
||||
|
||||
Reference in New Issue
Block a user