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.
This commit is contained in:
riccardom
2026-09-18 14:37:32 +02:00
parent 6565b8368e
commit d09e035d20
2 changed files with 34 additions and 16 deletions
@@ -16,10 +16,16 @@
(confirm against the signed pkg before fleet roll-out)
Distribution:
- sign with `productsign`, passing your "Developer ID Installer"
certificate to its sign flag,
before fleet roll-out (Apple-Configurator-2 won't install an
unsigned profile on Sonoma+ without user override).
- delivered through an MDM, the profile is signed by the MDM
channel itself; nothing to sign by hand,
- handed out any other way (Apple Configurator, double-click), it
installs unsigned and asks the user to confirm on recent macOS.
To avoid that, sign it as a CMS message with an identity the
target Macs trust:
security cms -S -N "Your Signing Identity" \
-i netbird-macos.mobileconfig -o signed.mobileconfig
Configuration profiles are not signed with productsign, which
handles installer packages.
- For local dev install: `sudo profiles install -path netbird-macos.mobileconfig`.
- For MDM (Jamf/Kandji/Mosyle/Intune): upload as a Custom Profile.
+24 -12
View File
@@ -259,13 +259,23 @@ JumpCloud, Apple Configurator 2, etc.).
preference domain.
3. Replace the placeholder `PayloadUUID` values with freshly generated
UUIDs (`uuidgen` on macOS) so each deployment has unique ids.
4. (Optional, recommended for production) sign the profile with your
organization's Developer ID Installer certificate using
`productsign` — unsigned profiles on Sonoma/Sequoia/Tahoe require
an extra user confirmation on install.
5. Upload the resulting `.mobileconfig` to your MDM as a **Custom
4. Upload the resulting `.mobileconfig` to your MDM as a **Custom
Configuration Profile** and scope it to the target device group.
Profiles delivered through an MDM are signed by the MDM channel itself,
so there is nothing to sign by hand for a managed rollout. A profile you
hand out some other way — Apple Configurator, or a double-click install —
installs unsigned and asks the user for an extra confirmation on recent
macOS releases. To avoid that, sign it 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. Note that configuration
profiles are **not** signed with `productsign`, which handles installer
packages, nor with an Apple Developer ID certificate.
Verify on a target device with:
```bash
@@ -403,10 +413,11 @@ both are accepted. Integers and strings behave as on desktop.
### When a policy takes effect
Every key is enforced on iOS: the ones that reshape the interface, and
the ones the engine applies to the connection itself. Getting there
takes one extra step that is worth understanding, because it decides
*when* a change lands.
Every key that applies to the platform is enforced on iOS: the ones that
reshape the interface, and the ones the engine applies to the connection
itself. (A handful have no iOS surface at all and are listed at the end
of this section.) Getting there takes one extra step that is worth
understanding, because it decides *when* a change lands.
iOS delivers the configuration to the NetBird app. The tunnel, though,
runs in a Network Extension — a separate process the system starts when
@@ -458,9 +469,10 @@ The table above is what the user sees. A second group of keys has no
control to lock, because the engine applies them straight to the
connection: `blockInbound`, `wireguardPort`, `lazyConnection`,
`allowRemoteJobs`, and `debugBundleUploadURL` when a remote job produces
a bundle. They are enforced just the same — a peer whose policy withholds
`allowRemoteJobs` refuses those jobs — there is simply nothing on screen
to mark yet.
a bundle. **On iOS** they are enforced just the same — a peer whose policy
withholds `allowRemoteJobs` refuses those jobs — there is simply nothing
on screen to mark. On tvOS none of them reach the engine, for the reason
in the warning above.
The rest do not apply to the platform and are parsed and ignored:
`allowServerSSH` (no SSH server on iOS), `disableServerRoutes` (an iOS