Skip to main content
The Ops Playbook

Self-Healing FileVault Key Escrow for macOS Fleets

Stop FileVault lockout tickets by automating recovery key rotation and Jamf Pro escrow with a launchd-scheduled zsh watcher and API workflow.

Self-Healing FileVault Key Escrow for macOS Fleets
Isla MorganIsla Morgan9 min readTier L235 min

This playbook covers

Share

#Current Method

In most macOS fleets, FileVault is enabled either through a configuration profile at enrolment or by an administrator running fdesetup enable interactively. Apple’s FileVault design generates a personal recovery key at encryption time and separately supports an institutional recovery key defined by a certificate. Many organisations rely on the personal-key model and expect it to be escrowed to Jamf Pro automatically through a FileVault escrow configuration profile. That escrow step depends on the device being unlocked, online, and able to report the key back at the moment it is generated or rotated. If the device is offline, the profile has not yet applied, or key generation happens outside the escrow window, the key is never captured and the Jamf Pro inventory record is left blank or stale.

When a user later forgets their account password, help desk staff attempt to retrieve the recovery key from Jamf Pro. If the escrow record is missing or out of date, there is no supported way to unlock the volume, and the fallback most teams use is a full erase and reimage rather than genuine recovery. This is a reactive process: nothing checks escrow completeness or key age until a lockout ticket is already open, and the only remediation available at that point is destructive.

#Improved Workflow

The improvement is to treat recovery-key escrow as a monitored state rather than a one-time event confirmed only at enrolment. A small zsh watcher, scheduled by launchd as a root-context LaunchDaemon, runs on a defined interval and performs three checks: whether FileVault is enabled (fdesetup status), whether a local marker records a previous successful escrow confirmation, and whether that marker’s age exceeds the organisation’s rotation policy. If FileVault is off, the watcher logs and exits without acting — automation should never attempt to enable or reconfigure encryption on a device where FileVault is deliberately or unexpectedly disabled; that condition is a stop condition requiring manual investigation, not a target for self-healing.

If FileVault is on and the marker is missing or stale, the watcher is intended to trigger a personal recovery key rotation and then confirm the new key is present in the Jamf Pro inventory record before writing a new local marker. Two specifics here are version- and configuration-sensitive and are not asserted as fixed behaviour in this article: the exact non-interactive credential requirements for fdesetup changerecovery on a given macOS release, and the exact Jamf Pro API endpoint and authentication scheme used to confirm an escrowed key on a given Jamf Pro version. Both must be confirmed against current Apple and Jamf documentation for the deployed OS and Jamf Pro instance before the rotation line is enabled in production; they are flagged for human review rather than stated as fact.

#Implementation

#
Prerequisites

  • A Jamf Pro instance with a FileVault escrow configuration profile already deployed to the target scope, and administrator access to confirm escrow behaviour on a test device.
  • A dedicated Jamf Pro API service account scoped only to the FileVault and computer-inventory privileges actually required, not a full administrator account.
  • Root access to install a LaunchDaemon; LaunchDaemons run as root system-wide, unlike LaunchAgents, which run only in a logged-in user’s session and cannot invoke fdesetup changerecovery reliably.
  • Confirmation, from current Apple platform documentation for the deployed macOS version, of the supported non-interactive invocation of fdesetup changerecovery.
  • A pilot device group in Jamf Pro, separate from the production fleet, for the first deployment cycle.

#
The Watcher Script

The script below shows the check-and-marker logic. The actual rotation invocation is deliberately left commented out and flagged, because its exact safe syntax depends on the deployed macOS version and must be validated before use; enabling it without that validation risks an unattended command failing silently or prompting for input that never arrives.

1#!/bin/zsh
2# FileVault escrow watcher - runs as root via LaunchDaemon
3MARKER="/var/db/org.filevault.escrow-marker"
4MAX_AGE_DAYS=90
5
6fv_status=$(fdesetup status)
7if [[ "$fv_status" != *"FileVault is On"* ]]; then
8  echo "$(date -u) FileVault not enabled - no action taken" >> /var/log/filevault-watcher.log
9  exit 0
10fi
11
12if [[ -f "$MARKER" ]]; then
13  marker_age_days=$(( ( $(date +%s) - $(cat "$MARKER") ) / 86400 ))
14else
15  marker_age_days=999999
16fi
17
18if (( marker_age_days < MAX_AGE_DAYS )); then
19  exit 0
20fi
21
22# Rotation requires a supported non-interactive credential path.
23# Confirm the exact fdesetup invocation against current Apple
24# documentation for the deployed macOS release before enabling.
25# fdesetup changerecovery -personal -outputplist > /var/db/org.filevault.newkey.plist
26
27escrow_confirmed=$(/usr/local/bin/confirm-jamf-escrow.sh)
28if [[ "$escrow_confirmed" == "true" ]]; then
29  date +%s > "$MARKER"
30  echo "$(date -u) Escrow confirmed, marker updated" >> /var/log/filevault-watcher.log
31else
32  echo "$(date -u) Escrow not confirmed - will retry next run" >> /var/log/filevault-watcher.log
33fi

#
The launchd Daemon

The plist installs at /Library/LaunchDaemons, owned by root:wheel with 644 permissions, and is loaded with launchctl bootstrap. It runs on a daily schedule rather than continuously, keeping the watcher’s footprint predictable for audit and troubleshooting.

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5  <key>Label</key>
6  <string>org.filevault.watcher</string>
7  <key>ProgramArguments</key>
8  <array>
9    <string>/bin/zsh</string>
10    <string>/Library/Application Support/org/filevault-watcher.zsh</string>
11  </array>
12  <key>StartCalendarInterval</key>
13  <dict>
14    <key>Hour</key>
15    <integer>7</integer>
16    <key>Minute</key>
17    <integer>0</integer>
18  </dict>
19  <key>RunAtLoad</key>
20  <false/>
21</dict>
22</plist>

#Guardrails

  • The Jamf Pro API service account used for escrow confirmation must be scoped to the minimum privilege needed to read and confirm a FileVault recovery key attribute, not a general administrator account, so a compromised script cannot be used to pivot into broader Jamf Pro control.
  • API credentials must live in the System keychain via security add-generic-password and be read at runtime with security find-generic-password; they must never be stored in plaintext inside the script or the LaunchDaemon plist.
  • The watcher must only update its local marker after escrow is confirmed by Jamf Pro, never immediately after rotation, so a failed confirmation leaves the device correctly flagged for another attempt rather than silently reporting success.
  • Key rotation must not run on every script execution; it should only trigger once the marker exceeds the organisation’s defined rotation age, to avoid unnecessary churn, audit noise and repeated user-credential prompts if a non-interactive path is not available.
  • Roll out to a pilot group first and observe at least one full escrow cycle before expanding scope to the production fleet.

#Validation

  1. Run fdesetup status on the endpoint and confirm it reports FileVault is on before assuming the watcher will act.
  2. After a scheduled run, check /var/log/filevault-watcher.log for a confirmed escrow entry with a current timestamp.
  3. Confirm the LaunchDaemon is loaded and healthy with launchctl print system/org.filevault.watcher, checking for a stable PID and no repeated crash-restart cycles.
  4. In Jamf Pro, confirm the device’s inventory record shows a recovery key rotation timestamp consistent with the local marker file.
  5. Review the Jamf Pro API service account’s audit activity to confirm calls occur only at the expected cadence, not as a retry storm indicating a failure loop.
  6. In the pilot group, confirm no device is left in a state where the local marker was updated without a corresponding Jamf Pro confirmation.

#Common Mistakes

  • Installing the watcher as a user LaunchAgent instead of a root LaunchDaemon, which prevents fdesetup changerecovery from running with the privilege it requires.
  • Embedding the Jamf Pro API credential in plaintext in the script or plist instead of the System keychain.
  • Allowing the script to rotate the recovery key on every run rather than gating rotation on the marker age, producing unnecessary key churn and audit noise.
  • Deploying fleet-wide before a pilot cycle, which turns any escrow API misconfiguration into simultaneous load and failure across the whole fleet at once.
  • Enabling the rotation command in the script before confirming its exact non-interactive syntax against current Apple documentation for the deployed macOS version.

#Recovery

  1. If the watcher or daemon behaves unexpectedly — repeated failures, unexpected rotations, or log entries that do not match observed device state — unload it immediately with launchctl bootout system/org.filevault.watcher and remove the plist, reverting the device to manual key management while the issue is investigated.
  2. If a rotation succeeds locally but Jamf Pro escrow confirmation fails, do not rotate again on the next run purely to retry; the script should re-attempt escrow confirmation of the existing new key rather than generating another key, to avoid leaving multiple ungoverned keys.
  3. Maintain an organisational fallback, such as a retained institutional recovery key or a documented key-retention policy, so a device is never left with zero recoverable key during the transition to automated rotation.
  4. If fdesetup status reports FileVault is off on a device the watcher expected to be encrypted, treat this as a stop condition: halt automation for that device and escalate for manual investigation rather than attempting any automated remediation.

#Measurable Outcome

The workflow is intended to reduce lockout tickets that are unresolvable because no valid recovery key was escrowed. The organisation should track, for its own fleet and ticketing system: the proportion of FileVault-enabled devices with a confirmed, current escrow timestamp in Jamf Pro before and after rollout; the volume of help desk tickets categorised as FileVault or recovery-key lockouts over a defined period before and after rollout; and the LaunchDaemon’s own run-success rate as a reliability indicator for the automation itself. No specific percentage or ticket-deflection figure is asserted here, because no organisation-specific ticketing data was supplied; any such figure must come from the organisation’s own before-and-after measurement, not from this article.

#Checklist

  • Jamf Pro FileVault escrow configuration profile deployed and confirmed working on a test device.
  • Dedicated, least-privilege Jamf Pro API service account created for escrow confirmation only.
  • API credential stored in the System keychain, not in the script or plist.
  • Watcher script installed at a fixed root-owned path with restrictive permissions.
  • LaunchDaemon plist installed under /Library/LaunchDaemons and loaded with launchctl bootstrap.
  • Rotation invocation validated against current Apple documentation for the deployed macOS version before being enabled.
  • Pilot group deployment completed and observed through at least one full escrow cycle.
  • Rollback procedure (launchctl bootout and plist removal) tested and documented before fleet-wide rollout.
Isla Morgan

Isla Morgan

Ops Playbook Architect

Isla Morgan is the macOS Platform Engineering Editor for The Ops Playbook, specialising in the design and day-to-day operation of secure, scalable enterprise Mac fleets. She covers Apple Business Manager, Automated Device Enrolment, declarative device management, Jamf Pro, Microsoft Intune, Platform SSO, FileVault key escrow, application packaging, update enforcement and shell-based support automation. Drawing on practical endpoint engineering and service operations, Isla explains how to turn Apple platform capabilities into dependable workflows for deployment, identity, compliance, observability and recovery. Her guidance balances strong security controls with the Mac user experience, using staged rollouts, measurable verification and tested rollback paths to keep changes safe at scale.

Published
View Profile
Reader Interaction

Comments

Add a thoughtful note on Self-Healing FileVault Key Escrow for macOS Fleets. Comments are checked for spam and held for moderation before appearing.

Loading comments...
Comment submission is disabled until Cloudflare Turnstile keys are configured.

Discover more

Learn More About KBY

Was this useful?

Operate smarter, with fewer recurring tickets.

Receive new operational playbooks, incident-prevention guidance, automation scripts and recovery runbooks.