Fleet Device Management
Fleet is an open-source device management platform that uses osquery to provide visibility and control over your device fleet. In Ghaf, Fleet Orbit is integrated to enable centralized device management, monitoring, and remote script execution.
Overview
Section titled “Overview”The Fleet integration in Ghaf provides:
- Device Visibility: Query device state, installed software, and system configuration
- Remote Management: Execute scripts and commands on managed devices
- Policy Enforcement: Define and monitor compliance policies
- Fleet Desktop: User-facing tray application for device status
Fleet Orbit runs in the GUI VM and reports to a central Fleet server using a dynamic hostname derived from the device hardware, ensuring consistent identification across reboots.
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────────────────┐│ Host VM ││ ┌─────────────────────────────────────────────────────┐ ││ │ ghaf-dynamic-hostname service │ ││ │ └─► /persist/common/ghaf/hostname │ ││ └─────────────────────────────────────────────────────┘ ││ │ (virtiofs) │└───────────────────────────┼─────────────────────────────────┘ │┌───────────────────────────┼─────────────────────────────────┐│ GUI VM ││ ▼ ││ ┌─────────────────────────────────────────────────────┐ ││ │ /etc/common/ghaf/hostname │ ││ └──────────────────────┬──────────────────────────────┘ ││ │ ││ ┌──────────────────────▼──────────────────────────────┐ ││ │ orbit.service │ ││ │ └─► ORBIT_HOSTNAME_FILE=/etc/common/ghaf/hostname │ ││ │ └─► Reports to Fleet Server │ ││ └─────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────┐ ││ │ fleet-desktop.service (user) │ ││ │ └─► Tray icon for device status │ ││ └─────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────┘Configuration
Section titled “Configuration”Fleet is configured in the GUI VM via services.orbit. The following example shows the default configuration:
services.orbit = { enable = true; fleetUrl = "https://your-fleet.example.com"; enrollSecret = "your-enroll-secret"; # Use enrollSecretPath for production hostnameFile = "/etc/common/ghaf/hostname"; # Dynamic hostname from host enableScripts = true; # Allow remote script execution};Configuration Options
Section titled “Configuration Options”| Option | Environment Variable | Description |
|---|---|---|
enable | — | Enable Fleet Orbit systemd service |
fleetUrl | ORBIT_FLEET_URL | Base URL of the Fleet server |
enrollSecret | ORBIT_ENROLL_SECRET | Enroll secret for Fleet server |
enrollSecretPath | ORBIT_ENROLL_SECRET_PATH | Path to enroll secret file (recommended for production) |
fleetCertificate | ORBIT_FLEET_CERTIFICATE | Path to Fleet server certificate chain |
hostnameFile | ORBIT_HOSTNAME_FILE | Path to file containing hostname (Ghaf-specific) |
hostIdentifier | ORBIT_HOST_IDENTIFIER | Host identifier mode: uuid or instance |
enableScripts | ORBIT_ENABLE_SCRIPTS | Enable remote script execution |
debug | ORBIT_DEBUG | Enable debug logging |
insecure | ORBIT_INSECURE | Disable TLS certificate verification |
Secret Management
Section titled “Secret Management”For production deployments, use enrollSecretPath with a secrets management solution like sops-nix:
services.orbit = { enable = true; fleetUrl = "https://fleet.example.com"; enrollSecretPath = config.sops.secrets.fleet-enroll-secret.path; hostnameFile = "/etc/common/ghaf/hostname";};
sops.secrets.fleet-enroll-secret = { sopsFile = ./secrets.yaml;};
For CI/dev images, keep secrets out of the image and inject the enroll secret atruntime. Ghaf uses a shared host path for dynamic hostname; you can reuse thesame mechanism for the enroll secret (for example, `/etc/common/ghaf/fleet/enroll`inside the guest).Dynamic Hostname
Section titled “Dynamic Hostname”Ghaf uses hardware-derived hostnames for device identification. The ghaf-dynamic-hostname service on the host generates a unique hostname based on hardware identifiers (DMI serial, disk UUID, or MAC address) and writes it to /persist/common/ghaf/hostname.
This file is shared with VMs via virtiofs and mounted at /etc/common/ghaf/hostname. The Fleet module is patched to read the hostname from this file via the hostnameFile option, ensuring devices are consistently identified on the Fleet server.
The orbit service includes a ConditionPathExists directive to wait for the hostname file before starting.
Systemd Services
Section titled “Systemd Services”Two systemd services are created:
orbit.service(system): Runs the Orbit agent, connecting to the Fleet serverfleet-desktop.service(user): Runs Fleet Desktop tray application in graphical sessions
Orbit logs are written to:
/var/log/orbit/orbit.log— Main Orbit log/var/log/orbit/osquery/— osquery result and status logsjournalctl -u orbit— Systemd journal
NixOS-Specific Considerations
Section titled “NixOS-Specific Considerations”The Ghaf Fleet integration includes patches for NixOS compatibility:
- Disabled auto-updates: NixOS manages packages declaratively; Orbit’s auto-update is disabled
- Disabled keystore: Secrets are not stored in OS-specific keystores
- Fixed paths: osqueryd binary path is set from Nix store
- Shebang patching: Remote scripts have shebangs patched to use NixOS paths
Troubleshooting
Section titled “Troubleshooting”Orbit not starting
Section titled “Orbit not starting”Check if the hostname file exists:
ls -la /etc/common/ghaf/hostnameCheck service status:
systemctl status orbitjournalctl -u orbit -fConnection issues
Section titled “Connection issues”Enable debug logging:
services.orbit = { debug = true; # For testing only: # insecure = true;};Script execution failures
Section titled “Script execution failures”Verify scripts are enabled and check logs:
cat /var/log/orbit/orbit.log | grep -i scriptReferences
Section titled “References”- Fleet Documentation
- osquery Documentation
- Dynamic Hostname Generation — Ghaf hardware-derived hostname system