Skip to content

Commit 59a41c2

Browse files
committed
fleet: add FleetDM client with dynamic hostname support
Add Fleet MDM client (Orbit) integration for device management: - Add fleet module with Orbit and Fleet Desktop packages (v1.46.0) - Patch orbit to support --hostname-file flag for dynamic hostname identification from external file instead of system hostname - Add NixOS-specific patches for script execution and path handling - Enable Orbit service in guivm with dynamic hostname from /etc/common/ghaf/hostname (shared via virtiofs from host) - Add systemd ConditionPathExists to wait for hostname file This allows Fleet server to identify devices using the hardware-derived dynamic hostname generated by ghaf-dynamic-hostname service on the host. Signed-off-by: vadik likholetov <vadikas@gmail.com>
1 parent 8f678b5 commit 59a41c2

File tree

19 files changed

+942
-1
lines changed

19 files changed

+942
-1
lines changed

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export default defineConfig({
9393
"ghaf/dev/ref/idsvm-development",
9494
"ghaf/dev/ref/systemd-service-config",
9595
"ghaf/dev/ref/dynamic-hostname",
96+
"ghaf/dev/ref/fleet",
9697
"ghaf/dev/ref/memory-wipe",
9798
"ghaf/dev/ref/kill_switch",
9899
"ghaf/dev/ref/wireguard-gui",

docs/src/content/docs/ghaf/dev/ref/dynamic-hostname.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ ghaf.identity.dynamicHostName.digits = 6; # 1 million possibilities
222222
- **User Visibility**: Users can identify their specific hardware instance across host and VMs
223223
- **Network Troubleshooting**: Consistent hostname helps with debugging network issues and tracking device behavior
224224
- **Reproducible Testing**: Deterministic identities allow consistent testing environments across rebuilds
225-
- **Fleet Management**: Same hardware always produces same identities for reliable device tracking
225+
- **Fleet Management**: Same hardware always produces same identities for reliable device tracking (see [Fleet Device Management](/ghaf/dev/ref/fleet))
226226

227227
## Technical Details
228228

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
title: Fleet Device Management
3+
sidebar:
4+
label: Fleet MDM
5+
---
6+
7+
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.
8+
9+
## Overview
10+
11+
The Fleet integration in Ghaf provides:
12+
13+
- **Device Visibility**: Query device state, installed software, and system configuration
14+
- **Remote Management**: Execute scripts and commands on managed devices
15+
- **Policy Enforcement**: Define and monitor compliance policies
16+
- **Fleet Desktop**: User-facing tray application for device status
17+
18+
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.
19+
20+
## Architecture
21+
22+
```
23+
┌─────────────────────────────────────────────────────────────┐
24+
│ Host VM │
25+
│ ┌─────────────────────────────────────────────────────┐ │
26+
│ │ ghaf-dynamic-hostname service │ │
27+
│ │ └─► /persist/common/ghaf/hostname │ │
28+
│ └─────────────────────────────────────────────────────┘ │
29+
│ │ (virtiofs) │
30+
└───────────────────────────┼─────────────────────────────────┘
31+
32+
┌───────────────────────────┼─────────────────────────────────┐
33+
│ GUI VM │
34+
│ ▼ │
35+
│ ┌─────────────────────────────────────────────────────┐ │
36+
│ │ /etc/common/ghaf/hostname │ │
37+
│ └──────────────────────┬──────────────────────────────┘ │
38+
│ │ │
39+
│ ┌──────────────────────▼──────────────────────────────┐ │
40+
│ │ orbit.service │ │
41+
│ │ └─► ORBIT_HOSTNAME_FILE=/etc/common/ghaf/hostname │ │
42+
│ │ └─► Reports to Fleet Server │ │
43+
│ └─────────────────────────────────────────────────────┘ │
44+
│ │
45+
│ ┌─────────────────────────────────────────────────────┐ │
46+
│ │ fleet-desktop.service (user) │ │
47+
│ │ └─► Tray icon for device status │ │
48+
│ └─────────────────────────────────────────────────────┘ │
49+
└─────────────────────────────────────────────────────────────┘
50+
```
51+
52+
## Configuration
53+
54+
Fleet is configured in the GUI VM via `services.orbit`. The following example shows the default configuration:
55+
56+
```nix
57+
services.orbit = {
58+
enable = true;
59+
fleetUrl = "https://your-fleet.example.com";
60+
enrollSecret = "your-enroll-secret"; # Use enrollSecretPath for production
61+
hostnameFile = "/etc/common/ghaf/hostname"; # Dynamic hostname from host
62+
enableScripts = true; # Allow remote script execution
63+
};
64+
```
65+
66+
### Configuration Options
67+
68+
| Option | Environment Variable | Description |
69+
|--------|---------------------|-------------|
70+
| `enable` || Enable Fleet Orbit systemd service |
71+
| `fleetUrl` | `ORBIT_FLEET_URL` | Base URL of the Fleet server |
72+
| `enrollSecret` | `ORBIT_ENROLL_SECRET` | Enroll secret for Fleet server |
73+
| `enrollSecretPath` | `ORBIT_ENROLL_SECRET_PATH` | Path to enroll secret file (recommended for production) |
74+
| `fleetCertificate` | `ORBIT_FLEET_CERTIFICATE` | Path to Fleet server certificate chain |
75+
| `hostnameFile` | `ORBIT_HOSTNAME_FILE` | Path to file containing hostname (Ghaf-specific) |
76+
| `hostIdentifier` | `ORBIT_HOST_IDENTIFIER` | Host identifier mode: `uuid` or `instance` |
77+
| `enableScripts` | `ORBIT_ENABLE_SCRIPTS` | Enable remote script execution |
78+
| `debug` | `ORBIT_DEBUG` | Enable debug logging |
79+
| `insecure` | `ORBIT_INSECURE` | Disable TLS certificate verification |
80+
81+
### Secret Management
82+
83+
For production deployments, use `enrollSecretPath` with a secrets management solution like sops-nix:
84+
85+
```nix
86+
services.orbit = {
87+
enable = true;
88+
fleetUrl = "https://fleet.example.com";
89+
enrollSecretPath = config.sops.secrets.fleet-enroll-secret.path;
90+
hostnameFile = "/etc/common/ghaf/hostname";
91+
};
92+
93+
sops.secrets.fleet-enroll-secret = {
94+
sopsFile = ./secrets.yaml;
95+
};
96+
```
97+
98+
## Dynamic Hostname
99+
100+
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`.
101+
102+
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.
103+
104+
The orbit service includes a `ConditionPathExists` directive to wait for the hostname file before starting.
105+
106+
## Systemd Services
107+
108+
Two systemd services are created:
109+
110+
- **`orbit.service`** (system): Runs the Orbit agent, connecting to the Fleet server
111+
- **`fleet-desktop.service`** (user): Runs Fleet Desktop tray application in graphical sessions
112+
113+
## Logs
114+
115+
Orbit logs are written to:
116+
- `/var/log/orbit/orbit.log` — Main Orbit log
117+
- `/var/log/orbit/osquery/` — osquery result and status logs
118+
- `journalctl -u orbit` — Systemd journal
119+
120+
## NixOS-Specific Considerations
121+
122+
The Ghaf Fleet integration includes patches for NixOS compatibility:
123+
124+
- **Disabled auto-updates**: NixOS manages packages declaratively; Orbit's auto-update is disabled
125+
- **Disabled keystore**: Secrets are not stored in OS-specific keystores
126+
- **Fixed paths**: osqueryd binary path is set from Nix store
127+
- **Shebang patching**: Remote scripts have shebangs patched to use NixOS paths
128+
129+
## Troubleshooting
130+
131+
### Orbit not starting
132+
133+
Check if the hostname file exists:
134+
```bash
135+
ls -la /etc/common/ghaf/hostname
136+
```
137+
138+
Check service status:
139+
```bash
140+
systemctl status orbit
141+
journalctl -u orbit -f
142+
```
143+
144+
### Connection issues
145+
146+
Enable debug logging:
147+
```nix
148+
services.orbit = {
149+
debug = true;
150+
# For testing only:
151+
# insecure = true;
152+
};
153+
```
154+
155+
### Script execution failures
156+
157+
Verify scripts are enabled and check logs:
158+
```bash
159+
cat /var/log/orbit/orbit.log | grep -i script
160+
```
161+
162+
## References
163+
164+
- [Fleet Documentation](https://fleetdm.com/docs)
165+
- [osquery Documentation](https://osquery.readthedocs.io/)
166+
- [Dynamic Hostname Generation](/ghaf/dev/ref/dynamic-hostname) — Ghaf hardware-derived hostname system

modules/common/identity/dynamic-hostname.nix

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,20 @@ let
146146
# Generate device-id from our hardware-derived ID (for backward compatibility)
147147
# Use the same ID but format as hex string with dashes like: 00-01-23-45-67
148148
printf "%010x" "$((10#$id))" | fold -w2 | paste -sd'-' | tr -d '\n' > "$shareDir/../device-id"
149+
150+
# Generate a stable UUID from the hardware key and export it for VMs.
151+
uuid_hash=$(echo -n "$key" | sha256sum | cut -d' ' -f1)
152+
uuid="''${uuid_hash:0:8}-''${uuid_hash:8:4}-5''${uuid_hash:13:3}-a''${uuid_hash:17:3}-''${uuid_hash:20:12}"
153+
printf "%s" "$uuid" > "$shareDir/uuid"
154+
155+
# Generate unique machine-ids for all VMs based on hardware ID
156+
# Each VM gets a deterministic ID derived from hardware + VM name
157+
${lib.concatMapStringsSep "\n" (vm: ''
158+
mkdir -p /persist/storagevm/${vm}/etc
159+
vm_key="$key-${vm}"
160+
vm_hash=$(echo -n "$vm_key" | sha256sum | cut -d' ' -f1)
161+
echo -n "$vm_hash" > /persist/storagevm/${vm}/etc/machine-id
162+
'') activeMicrovms}
149163
'';
150164
};
151165
in

modules/common/security/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
./pwquality.nix
1010
./fail2ban.nix
1111
./ssh-tarpit
12+
./fleet
1213
];
1314
}

0 commit comments

Comments
 (0)