Adds scripts for Windows and Ubuntu that checks the health of all fleetd
components and collects logs and recent events into a timestamped
archive for support and troubleshooting.
These have been used by multiple customers now, and has simplified the
collection of logs from multiple locations while including events that
can assist with troubleshooting. Adding to solutions for wider use.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49655
Documentation-only change. No server behavior changes.
## What's happening
On a personally-owned work profile (BYOD), Android applies the biometric
values of `keyguardDisabledFeatures` to the work profile lock. By
default the end user has one lock for both the work profile and the host
("Use one lock"), so there is no separate work profile lock to restrict,
and Android restricts the host's lock instead. Fingerprint and face
unlock turn off for the whole host, including the end user's personal
apps.
This is documented Android behavior, per
[`setKeyguardDisabledFeatures`](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,%20int)):
> `KEYGUARD_DISABLE_FINGERPRINT`, `KEYGUARD_DISABLE_FACE` or
`KEYGUARD_DISABLE_IRIS` which affects the managed profile challenge if
there is one, **or the parent user otherwise**.
Fleet never sets `keyguardDisabledFeatures` itself. Fleet's default
Android policy sets only `StatusReportingSettings`, and admin-authored
AMAPI policy is passed through as-is. The reason this still lands on
Fleet is that the profile in the bug report is byte-for-byte the example
Fleet publishes at
`docs/solutions/android/configuration-profiles/disable-face-and-biometrics-unlock.json`,
with no note about the BYOD side effect.
## What changed
- `articles/custom-os-settings.md`: new "Biometric unlock on
personally-owned (BYOD) hosts" subsection under "Special Android
behavior", covering the behavior and the configuration that scopes the
restriction to work.
- `docs/solutions/android/configuration-profiles/README.md`: entries for
the biometrics profile (carrying the caveat) and for the new example.
-
`docs/solutions/android/configuration-profiles/require-separate-work-profile-lock.json`:
new example using `passwordScope: SCOPE_PROFILE` and
`unifiedLockSettings: REQUIRE_SEPARATE_WORK_LOCK`.
The remedy needs no Fleet change: `passwordPolicies` is already in the
Android policy field mask
(`server/mdm/android/service/androidmgmt/policy_field_mask_test.go`), so
Fleet already delivers it.
## Testing
- [ ] QA'd all new/changed functionality manually
Docs-only, so no automated tests were added. Verification done:
- Both the new example profile and the combined snippet in the guide
decode into the real `androidmanagement.Policy` struct with
`DisallowUnknownFields`, confirming every key and nesting level matches
the AMAPI schema Fleet ships.
- The documented status flow (`USER_ACTION` non-compliance on
`passwordPolicies` marks the profile "Failed", then "Verified" once the
end user sets the work lock) is confirmed against
`server/mdm/android/service/pubsub_test.go`.
**Not yet verified on hardware.** I have not run the repro on a physical
BYOD Android host. Before merge, this is worth confirming:
1. On a BYOD Android host with fingerprint unlock configured and a work
profile enrolled, apply `disable-face-and-biometrics-unlock.json`.
Confirm fingerprint disappears as an unlock method device-wide.
2. Add the `passwordPolicies` block from
`require-separate-work-profile-lock.json` to that profile and re-upload.
Confirm Android prompts for a separate work profile lock, and that Fleet
shows the profile "Failed" with `USER_ACTION` on **Host > OS settings**
until the end user sets it.
3. After the end user sets the work lock, confirm the profile moves to
"Verified", fingerprint unlock works again on the personal side, and the
work profile still requires PIN/password.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an Android configuration profile option that requires a separate
lock for the work profile.
* Applies password policy settings specifically to the work profile
scope.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This enforces NTP on macOS devices.
The "Set date and time automatically" toggle can be verified with
`systemsetup - getusingnetworktime` (you can write a script to put the
output of that into a file, then use the `file_lines` table in a
policy), and set with `systemsetup - setusingnetworktime on` (which
could be a script automation that kicks off if a device fails the
policy).
If you want to prevent users from changing it, you can use the attached
config profile. Note that it requires setting the NTP server, but this
is most likely just the default Apple server. The `setusingnetworktime`
will work even with the Ul locked.
<img width="1458" height="320" alt="Screenshot 2026-05-14 at 08 19 28"
src="https://github.com/user-attachments/assets/22064715-1548-490c-b3e0-bde51dd26f12"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a macOS configuration profile that automatically configures
devices to use Apple’s time server.
* Included a human-readable profile name and standard configuration
metadata for easier deployment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Updated healthcheck command to support TLS configuration. accompanying
env.example sets FLEET_SERVER_TLS=true by default but our default test
in docker-compose.yml tests to http. Causes test to fail.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Closes https://github.com/fleetdm/fleet/issues/46927
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated service health monitoring to correctly probe the health
endpoint over HTTPS when TLS is enabled, and over HTTP when it is not.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- @noahtalerman: For Windows, I think we want to squeeze turning off MDM
and uninstalling fleetd into one script.
- Why? Because Fleet automatically turns on Windows MDM, two scripts
means Fleet could beat the IT admin and turn MDM back on before they
uninstall fleetd.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Windows fleetd uninstall now proactively detects and disables MDM
enrollment before removal to help ensure a cleaner device unenrollment.
* **Bug Fixes**
* Improved uninstall error reporting by surfacing the underlying failure
message and exiting with a clear non-zero code.
* **Chores**
* Updated fleet testing and workstation configurations: removed the
Windows uninstall/MDM-related steps from QA and workstation controls,
and added new Windows security/setup scripts plus additional
cross-platform post-install and extension installation tasks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Steven Palmesano <3100993+spalmesano0@users.noreply.github.com>
Adds a simple .sh script that can trigger a refetch locally from a host
if required.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated the Linux script used to trigger Fleet refetch operations. It
now runs with stricter Bash safety, validates and trims the system
identifier before sending the request, and reports clear success/failure
status while returning the appropriate nonzero exit code on errors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#46637
- Updated the wording and flow of the guide
- Included links to new configuration profiles in the solutions folder
- Added alternative option for enrolling in to cloud management
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added a Windows configuration profile to enable enrolling Google
Chrome into enterprise management.
* Included a template with a placeholder enrollment token for
administrators to replace when configuring device management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Noah Talerman <47070608+noahtalerman@users.noreply.github.com>
Removes docs/solutions/windows/scripts/install-yellowkey-extension.ps1
(thin wrapper that fetched Allen's upstream installer) and updates the
policy's run_script.path to install-windows-yellowkey-extension.ps1, the
canonical filename in allenhouchins/fleet-extensions. Users drop Allen's
installer (with its canonical name) into their GitOps scripts directory;
the policy references it directly.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** #46360
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated Windows YellowKey osquery Fleet policy documentation with
revised script references and remediation instructions for hosts that
fail to load the extension.
* **Chores**
* Removed obsolete installation script; installation procedures have
been consolidated for improved clarity and maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Adds detection and mitigation for YellowKey (CVE-2026-45585), an
unpatched BitLocker bypass affecting Windows 11, Server 2022, and Server
2025. This PR provides:
1. **Detection via osquery extension**: A policy that ensures the
`windows_yellowkey` extension is loaded, enabling daily reporting on
host exposure status
2. **Daily report**: Surfaces per-host YellowKey verdict (not affected,
mitigated, mitigated via WinRE disabled, BitLocker off, or exposed)
3. **Mitigation script**: Implements Microsoft's official mitigation by
stripping `autofstx.exe` from WinRE's `BootExecute` registry chain
4. **Installation script**: Downloads and registers the upstream
`windows_yellowkey` osquery extension from
`allenhouchins/fleet-extensions`
The user-facing article is tracked in a separate issue and will land in
its own PR. The `docs/solutions/all/queries/` → `reports/` directory
migration will also be done in a separate PR.
## Changes
### New files
- `docs/solutions/windows/scripts/mitigate-windows-yellowkey.ps1` —
PowerShell script that mounts WinRE, loads the offline SYSTEM hive,
strips `autofstx` from every ControlSet's `BootExecute`, verifies via
read-back, unmounts with commit, and re-seals the BitLocker measurement
chain via `reagentc /disable` + `/enable`. Writes
`HKLM\SOFTWARE\Fleet\YellowKey\BootExecMitigated = 1` on success. Exit
codes: 0 (done), 3 (OS not affected), 4 (failed).
- `docs/solutions/windows/scripts/install-yellowkey-extension.ps1` —
Wrapper that fetches and executes the upstream installer from
`allenhouchins/fleet-extensions/main`. The upstream script handles
download, PE-header validation, service stop/restart, ACL hardening, and
loader registration. This wrapper exists only because Fleet's GitOps
`run_script` requires a file on disk.
-
`docs/solutions/windows/policies/windows-yellowkey-extension.policies.yml`
— Policy that checks `osquery_registry` for the `windows_yellowkey`
table. Passes when loaded; failing hosts run the installer.
- `docs/solutions/windows/reports/windows-yellowkey.reports.yml` — Daily
report querying the extension's `state`, `state_reason`, `needs_action`,
`winre_enabled`, `tpm_only`, and `mitigated` columns.
## Design notes
- **No opt-in gate**: Microsoft's `autofstx` strip is safe on every
affected host, so the mitigation script runs unconditionally.
- **One-way mitigation**: No unmitigate path. When Microsoft ships a
patch, apply it and clear the marker.
- **Extension sourcing**: The extension binary and installer live
upstream in `allenhouchins/fleet-extensions/windows_yellowkey`. Allen's
CI republishes on every push to `main`. The installer always pulls from
`releases/latest/download`, so no edits to this repo are needed when the
binary updates.
- **Loader path**: The installer writes to `C:\Program
Files\osquery\extensions.load` (osquery's compiled default), not to
orbit's directory, avoiding conflicts with TUF-managed extensions.
- **Hive and mount cleanup**: Mount, hive load, edit, and unmount all
run inside a single try/finally block to ensure cleanup even on
exception.
- **Read-back verification**: Each ControlSet's `BootExecute` is
verified after the strip to confirm.
https://claude.ai/code/session_016QZzDFsd1hTrYkQukGon6Y
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added Windows YellowKey BitLocker bypass vulnerability detection and
reporting capabilities
* New policy to verify security extension installation and status on
Windows hosts
* New report surfaces vulnerability exposure and state across Windows
fleet
* Added automated remediation for vulnerable hosts, including extension
installation and bypass mitigation procedures
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46358?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude <noreply@anthropic.com>
For article #45967: Rollout rings with Fleet labels.
Adds three drop-in label YAML files under docs/solutions/all/labels/:
rollout-rings.labels.yml — five cumulative dynamic labels (1%, 5%, 25%,
75%, 100%) for gradual software rollouts via labels_include_any. Each
ring is a superset of the previous.
rollout-waves.labels.yml — five disjoint dynamic labels covering the
same percentage breakpoints, for A/B experiments and per-wave reporting.
pinned-canaries.labels.yml — manual label for pinning specific hosts
(dev Macs, QA machines) into the first wave regardless of their natural
UUID shard.
All three use the same deterministic UUID-based shard expression
(positions 10 and 25, avoiding RFC 4122's fixed version/variant digits
at positions 15 and 20) so a host's ring assignment never changes across
reboots or agent reinstalls.
New folder docs/solutions/all/labels/ follows the existing pattern of
docs/solutions/all/policies/ and docs/solutions/all/queries/.
The companion article is in draft and will follow in a separate PR; it
references these files via
https://github.com/fleetdm/fleet/blob/main/docs/solutions/all/labels/...
URLs.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **Documentation**
* Added comprehensive labeling solutions for managing staged rollouts:
manual pinned canaries for selecting priority hosts, cumulative rollout
rings covering multiple deployment phases (1%, 5%, 25%, 75%, 100%), and
partitioned rollout waves for balanced phased distribution strategies.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45971?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adding documented profiles for PSSO simplified setup. These are
specifically for the macOS 26+ feature, though most of what's in them is
also applicable to lower versions
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **Documentation**
* Added example configuration profiles for macOS SSO extension setup
with Entra and Okta platforms.
[](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45157)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Multiple customers have now requested scripts for setting hostnames on
macOS, and a couple for Linux. This adds scripts to the solutions folder
for that purpose.
Linux tested against `Ubuntu 26.04` and `openSUSE Tumbleweed`
macOS tested against `Tahoe 26.4.1`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added an automated Linux hostname configuration solution that derives
a hostname from the device serial, applies it system-wide, and updates
host entries.
* Added an automated macOS hostname configuration solution that sets
ComputerName/LocalHostName/HostName from the device serial and reports
the new hostname.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
When importing CIS benchmark content for multiple OS versions into a
single
Fleet team via GitOps, users encounter several hard validation failures
because
Fleet enforces uniqueness on script basenames, mobileconfig
PayloadDisplayName /
PayloadIdentifier, and policy name fields.
Changes (all confined to docs/solutions/cis/):
- Fix #!/usr/bin/env bash shebang in CIS_2.6.7.sh (macOS 13/14/15) ->
#!/bin/bash
- Prefix script filenames with OS slug (macos13-, macos14-, macos15-,
win10-,
win11-, win11-intune-) to prevent basename collisions
- Prefix mobileconfig PayloadDisplayName with OS tag ([macOS 13] etc.),
which
is the field Fleet uses for identity
- Prefix mobileconfig PayloadIdentifier with an OS slug so identifiers
stay
unique across versions
- Prefix every policy name: field with the OS tag; preserve original
YAML
formatting (plain, single-quoted with '' escapes, and folded block
scalars)
- Rename Windows XML profiles with win10-, win11-, and win11-intune-
prefixes
None of these changes affect the security logic or coverage of the
benchmarks.
They only make the content importable without manual intervention.
Co-authored-by: Claude <noreply@anthropic.com>
Add fallback wipe script for Windows hosts (#34994)
When Fleet's built-in Windows wipe action fails (MDM command returns
status 500, device not wiped), there is no documented fallback. This PR
adds a script that can be run via Fleet to wipe the device when the
native wipe fails.
## Changes
- `docs/solutions/windows/scripts/wipe-windows-device.ps1` - Fallback
wipe script
- `articles/lock-wipe-hosts.md` - Reference to fallback script added
under Windows wipe section
## What the script does
1. Validates and repairs WinRE if disabled (confirmed root cause of wipe
failures in #34994)
2. Checks Component Store integrity via DISM
3. Suspends BitLocker for one reboot cycle
4. Triggers wipe via WMI-to-CSP bridge (`doWipeProtected`, falls back to
`doWipe`), bypassing the MDM command queue
Fully unattended. No user interaction required. Exits 0 on success, 1 on
failure.
## Context
Every fully unattended Windows wipe method uses the same RemoteWipe CSP.
There is no alternative Windows API. This script adds value by fixing
the root causes before calling the wipe, and by bypassing the MDM
command queue where server-side failures (DB timeouts, auth errors) can
occur.
Closes#34994
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an administrator-only Windows device wipe utility that performs
staged system checks (recovery environment, system health, and disk
protection), attempts to suspend drive protection for a reboot, invokes
multiple local wipe triggers with fallbacks, creates a timestamped audit
log of actions, and provides clear success/failure summaries with likely
causes and suggested next steps.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Marko Lisica <83164494+marko-lisica@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
## Summary
Migrates CIS benchmark files from `ee/cis/` to `docs/solutions/cis/` in
Fleet GitOps-compatible format, with configuration profiles, remediation
scripts, and policy queries for macOS 13/14/15, Windows 10/11, and
Windows 11 Intune.
**The original AI-generated content (commits 1–4) contained critical
errors that would cause silent deployment failures.** Commits 5–10 are a
systematic review that validates every CSP path, Apple payload key, and
script against official vendor documentation — fixing 30+ issues.
---
## What was wrong and why
### 1. Windows XML profiles used wrong SyncML format (would be rejected
by Fleet)
The AI generated full SyncML protocol envelopes
(`<SyncML><SyncBody><CmdID>…<Final/>`), but Fleet expects flat
`<Replace><Item>…</Item></Replace>` blocks — the same format used in
[`docs/solutions/windows/configuration-profiles/`](https://github.com/fleetdm/fleet/tree/main/docs/solutions/windows/configuration-profiles).
Every production Fleet profile (e.g., [`enforce device password and lock
requirements –
[Bundle].xml`](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/configuration-profiles/enforce%20device%20password%20and%20lock%20requirements%20%E2%80%93%20%5BBundle%5D.xml))
uses this flat format. This is the same class of error [reported by
@AdamBaali in
#42748](https://github.com/fleetdm/fleet/issues/42748#issuecomment-4223794562)
when testing the `numa` AI-generated security baseline.
**Fix:** Rewrote all 13 XML files to match Fleet's expected format.
### 2. Six Audit CSP names were fabricated (`LogonLogoff_` prefix
doesn't exist)
The AI used `Audit/LogonLogoff_AuditLogon` etc., but the [Microsoft
Audit Policy CSP
documentation](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-audit)
specifies the prefix `AccountLogonLogoff_` — e.g.,
`Audit/AccountLogonLogoff_AuditLogon`. Using the wrong prefix returns
HTTP 500 from the MDM server.
**Fix:** Corrected all 6 across 3 platform variants (18 replacements).
### 3. Three Apple Intelligence profiles used fabricated payload keys
The AI invented keys that don't exist in [Apple's device-management
reference](https://github.com/apple/device-management/blob/release/mdm/profiles/com.apple.applicationaccess.yaml):
| Profile | AI-generated (fabricated) | Correct per Apple reference |
|---------|--------------------------|----------------------------|
| Extensions | `allowIntelligenceExtensions` |
`allowExternalIntelligenceIntegrations` |
| Mail | `com.apple.mail` / `allowMailIntelligence` |
`com.apple.applicationaccess` / `allowMailSmartReplies` +
`allowMailSummary` |
| Notes | `com.apple.mobilenotes` / `allowNotesIntelligence` |
`com.apple.applicationaccess` / `allowNotesTranscription` +
`allowNotesTranscriptionSummary` |
These profiles would deploy silently but enforce nothing — the keys
would be ignored by macOS. The corresponding policy SQL queries also
referenced the fabricated keys, so compliance checks would never pass
even with the profile applied.
**Fix:** Corrected keys, domains, and the corresponding policy SQL
queries so compliance checks match what the profiles actually enforce.
### 4. Firewall CSP used wrong URI prefix
AI used `./Device/Vendor/MSFT/Firewall/MdmStore/…` but [Microsoft's
Firewall CSP
documentation](https://learn.microsoft.com/en-us/windows/client-management/mdm/firewall-csp)
and Fleet's own production profiles use
`./Vendor/MSFT/Firewall/MdmStore/…`.
**Fix:** Updated all firewall URIs across 3 platform variants.
### 5. Wrong SIDs in user rights deny policies
CIS 2.2.16 (Deny access from network) and 2.2.20 (Deny RDP logon)
require denying both **Guests** (`S-1-5-32-546`) and **Local account**
(`S-1-5-113`). The AI only included Guests. This is the same error
[identified by @AdamBaali in
#42748](https://github.com/fleetdm/fleet/issues/42748#issuecomment-4223794562)
where the `numa` baseline used `S-1-2-0` (wrong SID entirely).
**Fix:** Added `S-1-5-113` to both XML profiles and PS1 scripts.
### 6. macOS scripts had runtime-breaking bugs
Scripts copied from `ee/cis/` originals contained issues that would
cause failures when deployed via Fleet:
| Issue | Scripts affected | Impact |
|-------|-----------------|--------|
| Hardcoded `<username>` placeholder | CIS_6.1.1, CIS_6.3.6, CIS_2.11.1,
CIS_2.6.2 | Shell error — `<username>` parsed as redirect |
| Missing `chmod 0440` on sudoers drop-ins | CIS_5.4, CIS_5.5 | macOS
sudo silently ignores files without 0440 perms |
| `sudo IFS=$'\n'` doesn't set IFS in current shell | CIS_5.1.5,
CIS_5.1.6, CIS_5.1.7 | Word splitting breaks on paths with spaces |
| Unsafe temp files (`./tmp.txt` in CWD) | CIS_3.2, CIS_3.3, CIS_3.4 |
Race condition, fails in read-only CWD |
| Missing shebang | CIS_2.6.1.2 | May use wrong shell interpreter |
| `not_always_working` scripts with `<password>` | CIS_2.10.1,
CIS_2.10.2 | Could never work in automated deployment |
**Fix:** Rewrote scripts with dynamic user enumeration, `mktemp`, proper
IFS, `visudo` validation. Removed `not_always_working` scripts.
### 7. Policy YAML formatting bugs and spelling
- **Computer Browser policy** (win-10, win-11): `resolution: |` was on
the same line as description text, causing YAML to swallow the entire
resolution into the description — no remediation steps shown.
- **Set Time and Date policy** (macOS 13/14/15): Empty `description:`
parsed as `null`.
- 14 spelling errors across macOS and Windows YAML (`existance`,
`Extention` ×8, `recomendation`, `bellow`, `enableds`, `addess` ×2,
etc.)
- Filename inconsistencies: `on-device-dictiation-enabled` (typo),
`2.8.1.disable` (dots vs dashes)
---
## Verification methodology
Every CSP OMA-URI and Apple payload key was validated against official
vendor documentation:
| Category | Count | Source | Result |
|----------|-------|--------|--------|
| [Audit
CSP](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-audit)
| 27 | Microsoft docs | 6 corrected |
| [UserRights
CSP](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-userrights)
| 27 | Microsoft docs | All verified correct |
| [LocalPoliciesSecurityOptions
CSP](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-localpoliciessecurityoptions)
| 27 | Microsoft docs | 1 format corrected |
| [Firewall
CSP](https://learn.microsoft.com/en-us/windows/client-management/mdm/firewall-csp)
| 14 | Microsoft docs | All correct (after path fix) |
| [Defender
CSP](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-defender)
| 9 | Microsoft docs | All verified correct |
| [Apple
applicationaccess](https://github.com/apple/device-management/blob/release/mdm/profiles/com.apple.applicationaccess.yaml)
| 13 profiles | Apple device-management repo | 3 corrected |
| Fleet GitOps YAML | 1,857 policies | [Fleet GitOps
docs](https://fleetdm.com/docs/configuration/yaml-files) | 2 format bugs
fixed |
| Fleet XML format | 13 files |
[`docs/solutions/windows/`](https://github.com/fleetdm/fleet/tree/main/docs/solutions/windows/configuration-profiles)
| Reformatted to match |
| Fleet blocked CSPs | — | `server/fleet/windows_mdm.go` | No conflicts
|
| [#43598](https://github.com/fleetdm/fleet/issues/43598) glob bug | 305
files | Filename scan | No `*`, `?`, `[`, `{` in any filename |
## Commits
1. `89d9418` — Copy CIS benchmarks to docs/solutions/cis/ in
GitOps-compatible format
2. `bbabb13` — Restructure with policies/, configuration-profiles/,
scripts/ subdirs
3. `00004f4` — Promote test artifacts, add Contents to READMEs
4. `786591f` — Add configuration profiles and scripts to all CIS
benchmark platforms
5. `0a47a53` — Fix macOS scripts (username placeholders, sudoers perms,
IFS, temp files, shebang, dictation typo, remove broken scripts)
6. `4efbd40` — Reformat all 13 Windows XML profiles to Fleet's flat
Replace/Item format, fix Firewall CSP paths, fix SIDs
7. `f0abb66` — Fix 6 Audit CSP names: `LogonLogoff_` →
`AccountLogonLogoff_`
8. `bfb0f95` — Fix `SmartCardRemovalBehavior` format type (`int` →
`chr`)
9. `4cbb33e` — Fix 3 Apple Intelligence profiles (fabricated keys → real
Apple keys), fix YAML formatting bugs
10. `d3a0031` — Fix spelling (14 corrections), naming conventions,
policy-profile key alignment
## Current state
| Platform | Policies | Config Profiles | Scripts |
|----------|----------|-----------------|---------|
| macOS 13 | 1 YAML (111 policies) | 46 .mobileconfig | 43 .sh |
| macOS 14 | 1 YAML (111 policies) | 47 .mobileconfig | 43 .sh |
| macOS 15 | 1 YAML (113 policies) | 43 .mobileconfig | 44 .sh |
| Windows 10 | 1 YAML (510 policies) | 4 SyncML XML | 5 .ps1 |
| Windows 11 | 1 YAML (555 policies) | 4 SyncML XML | 5 .ps1 |
| Windows 11 Intune | 3 YAML (457 policies) | 5 SyncML XML | 2 .ps1 |
The source files in `ee/cis/` are intentionally left untouched.
https://claude.ai/code/session_01DUqJK6iJ8MWMdz2d25ZTNW
---------
Co-authored-by: Claude <noreply@anthropic.com>
The SCEP profile for NDES certificate authority requires the
$FLEET_VAR_SCEP_RENEWAL_ID variable in the Subject OU field. Without
this, GitOps runs fail with an error about missing variables.
https://claude.ai/code/session_01DW2rrUmrxsTaD3t5J66Xz4
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [ ] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [ ] Added/updated automated tests
- [ ] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [ ] QA'd all new/changed functionality manually
For unreleased bug fixes in a release candidate, one of:
- [ ] Confirmed that the fix is not expected to adversely impact load
test results
- [ ] Alerted the release DRI if additional load testing is needed
## Database migrations
- [ ] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [ ] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [ ] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).
## New Fleet configuration settings
- [ ] Setting(s) is/are explicitly excluded from GitOps
If you didn't check the box above, follow this checklist for
GitOps-enabled settings:
- [ ] Verified that the setting is exported via `fleetctl
generate-gitops`
- [ ] Verified the setting is documented in a separate PR to [the GitOps
documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485)
- [ ] Verified that the setting is cleared on the server if it is not
supplied in a YAML file (or that it is documented as being optional)
- [ ] Verified that any relevant UI is disabled when GitOps mode is
enabled
## fleetd/orbit/Fleet Desktop
- [ ] Verified compatibility with the latest released version of Fleet
(see [Must
rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md))
- [ ] If the change applies to only one platform, confirmed that
`runtime.GOOS` is used as needed to isolate changes
- [ ] Verified that fleetd runs on macOS, Linux and Windows
- [ ] Verified auto-update works from the released version of component
to the new version (see [tools/tuf/test](../tools/tuf/test/README.md))
Co-authored-by: Claude <noreply@anthropic.com>
The script now correctly sets the 'idp' source when updating device
mappings, which updates the IDP username field that Fleet uses for
profile variables and IDP-related features, rather than adding to the
'other emails' field.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42226
When doing dev in a remote environment, like a public cloud VM, don't
expose ports to the public.
This is a contributor security improvement.
The localstack fail is present on main, and was not caused by this
change:
https://github.com/fleetdm/fleet/actions/runs/23439965808/job/68187858627
# Checklist for submitter
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Docker Compose configuration updated across multiple services (Redis,
MySQL, mail, monitoring, and storage services) to restrict port bindings
to localhost only instead of all network interfaces.
* Documentation Docker Compose examples updated to reflect
localhost-only port binding for core services.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adds `docs/solutions/api-scripts/sync_jamf_users_to_fleet.py`, a Python
script that:
- Scrapes every computer in Jamf Pro via the Classic API
(`/JSSResource/computers/subset/basic`)
- Pulls the assigned user's email (falls back to username if no email is
set)
- Matches each device to a Fleet host by serial number
- Assigns that user to the host in Fleet via `PUT
/api/v1/fleet/hosts/:id/device_mapping`
Features:
- Supports both OAuth 2.0 client credentials and username/password auth
for Jamf
- `--dry-run` flag to preview changes without modifying Fleet
- Summary statistics on completion (assigned, skipped, errors)
Resolvesfleetdm/confidential#14972
## Summary
- Adds Fleet's dynamic SCEP challenge (Okta CA with a dynamic challenge,
available since Fleet 4.81.0) as the recommended path for Device Access
certificates on macOS 14+
- Preserves static SCEP as a documented legacy option, each with its own
downloadable example profile
- Adds `okta-device-access-scep-dynamic-example.mobileconfig` using
`$FLEET_VAR_NDES_SCEP_PROXY_URL` and `$FLEET_VAR_NDES_SCEP_CHALLENGE`;
existing static example profile unchanged
- Corrects renewal claim: neither static nor dynamic SCEP supports
automatic certificate renewal per Okta's own documentation — both
require profile redeployment before expiration
- Adds Okta documentation links throughout for proper SEO and
cross-reference:
- [Use Okta as a CA for Device
Access](https://help.okta.com/oie/en-us/content/topics/oda/oda-as-scep-okta-ca.htm)
- [Configure Okta as a CA with a dynamic SCEP
challenge](https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/okta-ca-dynamic-scep-macos-jamf.htm)
- [Configure Okta as a CA with a static SCEP
challenge](https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/okta-ca-static-scep-macos-jamf.htm)
- Uses correct Fleet UI path and CA type name verified against
`helpers.tsx` and the 4.81.0 release article
- Uses Okta's exact field names (SCEP URL, Challenge URL, Username,
Password) verified from Okta's documentation
- Updates `publishedOn` to reflect the revision date
## Files changed
- `articles/deploying-okta-platform-sso-with-fleet.md` — article update
-
`docs/solutions/macos/configuration-profiles/okta-device-access-scep-dynamic-example.mobileconfig`
— new dynamic SCEP example profile
-
`docs/solutions/macos/configuration-profiles/okta-device-access-scep-example.mobileconfig`
— unchanged (static example)
## Test plan
- [ ] Article renders correctly on fleetdm.com preview
- [ ] Dynamic example profile link resolves:
`okta-device-access-scep-dynamic-example.mobileconfig`
- [ ] Static example profile link resolves:
`okta-device-access-scep-example.mobileconfig`
- [ ] All Okta documentation links resolve
- [ ] Fleet UI path verified: **Settings → Integrations → Certificate
authorities → Add CA → Okta CA or Microsoft Device Enrollment service
(NDES)**
- [ ] Fleet variables `$FLEET_VAR_NDES_SCEP_PROXY_URL` and
`$FLEET_VAR_NDES_SCEP_CHALLENGE` confirmed in Fleet docs
- [ ] Meta tags present with updated `publishedOn` date
- [ ] Style guide compliance verified (active voice, bold UI elements,
no marketing fluff)
- Add install ChatGPT script.
- Update turn on MDM script with some changes from the script above.
I tested the turn on MDM script after making these updates.
Updated web clip template to match what we do in dogfood, except it's
using Fleet logo as an icon.
I also created a base64 icon as a single line to improve readability.
I removed the "full screen" option, so self-service now opens in the
default browser. This way, if a customer uses Jira or a similar tool as
the organization support URL, they don't need to re-authenticate.
@ddribeiro After talking with Noah about troubleshooting and logs, I
thought it would be good if we created a user-facing guide for
troubleshooting. Our CSEs frequently send the same troubleshooting
information to customers when they report issues. We can empower
customers with one resource that they can work through, reducing the
significant amount of time in back-and-forth steps sent over Slack.
Also, we've talked about pulling the "Finding fleetd logs" section out
of the [Enroll hosts](https://fleetdm.com/guides/enroll-hosts) guide.
Perhaps when this is complete, we can link to this document from that
guide.
This certainly doesn't contain everything! Please bring the CSEs in to
flesh this out since they're in the day-to-day and have much more
knowledge regarding this than I do.
---------
Co-authored-by: Brock Walters <153771548+nonpunctual@users.noreply.github.com>
Closes#38916
Related: #34993, #33985, fleetdm/confidential#13228
## Changes
**Article update** (`articles/windows-mdm-setup.md`)
- Adds "Migrating from another MDM solution" subsection under **Manual
enrollment** with overview of common migration issues and links to
remediation scripts
**New scripts** (`docs/solutions/windows/scripts/`)
- `reset-mdm-enrollment-flag.ps1` — Resets MmpcEnrollmentFlag blocking
MDM status after migration
- `remove-stale-mdm-enrollment-records.ps1` — Clears orphaned enrollment
GUIDs, AAD discovery cache, and MS DM Server cache
- `fix-workplace-join-configuration.ps1` — Re-enables
Automatic-Device-Join task and configures Workplace Join policies
- `remove-unreachable-wsus-configuration.ps1` — Removes unreachable WSUS
server config that breaks Windows Update
## Context
Customers migrating Windows hosts from Intune to Fleet have been hitting
recurring enrollment issues, MDM status stuck on "Off," enrollment
errors (`0x80190190`, `0x8018000a`), and Windows Update breakage from
leftover RMM agents. These scripts consolidate the workarounds from
multiple customer engagements into self-serve remediation that can be
deployed via **Controls > Scripts**.
---------
Co-authored-by: Marko Lisica <83164494+marko-lisica@users.noreply.github.com>
Discussed at
https://macadmins.slack.com/archives/C0214NELAE7/p1769719765777279
- The endpoints for marking a device as unmanaged and sending an
unmanage command were deprecated and no longer work. The endpoint for
looking up a device by serial number was also deprecated, so I've
proactively updated it.
- The whole story is now refactored and simplified.
- Also fixed a link in the `tines` README.
This pull request updates the Okta Verify on Windows SCEP configuration
documentation and profile to simplify deployment with Fleet and reduce
manual steps. The changes make the process more reliable by
standardizing variable usage, improving instructions, and automating
certificate enrollment.
**Key improvements and changes:**
**Documentation and workflow simplification:**
- The guide in
`articles/enable-okta-verify-on-windows-using-a-scep-configuration-profile.md`
was rewritten for clarity and to reflect the new automated approach.
Manual editing of XML and scripts is no longer needed; Fleet-managed
variables and secrets now handle all required values. Steps for
gathering prerequisites, deploying, verifying, and renewing certificates
are streamlined, and troubleshooting guidance is expanded.
- The subject name in the certificate is now set to use the hardware
serial (`$FLEET_VAR_HOST_HARDWARE_SERIAL`) instead of the host UUID,
improving uniqueness and traceability.
([docs/solutions/windows/configuration-profiles/install Okta attestation
certificate -
[Bundle].xmlL77-R89](diffhunk://#diff-d8fc2c8add5725599bdc41a7b417dc3978cfc34eb6fcb8950db513f2b5799aa5L77-R89))
**Secret management and security:**
- The configuration profile now references Fleet secrets
(`$FLEET_SECRET_OKTA_SCEP_URL`, `$FLEET_SECRET_OKTA_SCEP_CHALLENGE`,
`$FLEET_SECRET_OKTA_CA_THUMBPRINT`) directly, removing the need for
manual substitution and reducing risk of misconfiguration.
([docs/solutions/windows/configuration-profiles/install Okta attestation
certificate -
[Bundle].xmlL98-R141](diffhunk://#diff-d8fc2c8add5725599bdc41a7b417dc3978cfc34eb6fcb8950db513f2b5799aa5L98-R141))
**Automated certificate enrollment:**
- An `<Exec>` command is added to the XML profile to automatically
trigger SCEP enrollment upon deployment, further reducing manual
intervention. ([docs/solutions/windows/configuration-profiles/install
Okta attestation certificate -
[Bundle].xmlL98-R141](diffhunk://#diff-d8fc2c8add5725599bdc41a7b417dc3978cfc34eb6fcb8950db513f2b5799aa5L98-R141))
These changes make the Okta Verify SCEP configuration for Windows much
easier to deploy and maintain, with improved automation and clearer
instructions.
---------
Co-authored-by: Brock Walters <153771548+nonpunctual@users.noreply.github.com>