From 5ac162cc0a49c3216bf2ce9e2a559b14428d22df Mon Sep 17 00:00:00 2001 From: denys-gif Date: Thu, 13 Aug 2026 11:51:11 +0100 Subject: [PATCH] fix: orbit host info --- client/orbit_client.go | 3 ++ orbit/cmd/orbit/orbit.go | 77 +++++++++++++++++++++++++++++++--- orbit/pkg/constant/constant.go | 3 ++ server/fleet/api_orbit.go | 3 ++ server/fleet/orbit.go | 3 ++ server/service/orbit.go | 9 ++++ 6 files changed, 92 insertions(+), 6 deletions(-) diff --git a/client/orbit_client.go b/client/orbit_client.go index b21f496dcfb..9e4ef794d15 100644 --- a/client/orbit_client.go +++ b/client/orbit_client.go @@ -580,6 +580,9 @@ func (oc *OrbitClient) enroll() (string, error) { ComputerName: oc.hostInfo.ComputerName, HardwareModel: oc.hostInfo.HardwareModel, EUAToken: oc.euaToken, + // >>> OPENFRAME(agent-openframe-mode): carry osquery's instance id — openframe/docs/agent-openframe-mode.md + InstanceID: oc.hostInfo.InstanceID, + // <<< OPENFRAME(agent-openframe-mode) } var resp fleet.EnrollOrbitResponse err := oc.request(verb, path, params, &resp) diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index 7b2845e3d48..24418247bcb 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -900,6 +900,26 @@ func orbitAction(c *cli.Context) error { orbitHostInfo.OsqueryIdentifier = osqueryHostInfo.InstanceID } + // >>> OPENFRAME(agent-openframe-mode): instance id for clone diagnostics — openframe/docs/agent-openframe-mode.md + if c.Bool("openframe-mode") { + orbitHostInfo.InstanceID = osqueryHostInfo.InstanceID + } + // <<< OPENFRAME(agent-openframe-mode) + + // >>> OPENFRAME(agent-openframe-mode): persist the enrolled identifier for `orbit uuid` — openframe/docs/agent-openframe-mode.md + if c.Bool("openframe-mode") { + enrolledIdentifier := orbitHostInfo.OsqueryIdentifier + if enrolledIdentifier == "" { + enrolledIdentifier = orbitHostInfo.HardwareUUID + } + if enrolledIdentifier != "" { + if err := writeOsqueryIdentifierFile(c.String("root-dir"), enrolledIdentifier); err != nil { + log.Error().Err(err).Msg("write osquery identifier file") + } + } + } + // <<< OPENFRAME(agent-openframe-mode) + var ( options []osquery.Option // optionsAfterFlagfile is populated with options that will be set after the '--flagfile' argument @@ -2738,14 +2758,31 @@ var uuidCommand = &cli.Command{ } } - // Use temporary database for UUID query - tmpDBPath := filepath.Join(os.TempDir(), fmt.Sprintf("orbit-uuid-%s", uuid.NewString())) - defer os.RemoveAll(tmpDBPath) + // >>> OPENFRAME(agent-openframe-mode): prefer the enrolled identifier; a throwaway osquery DB + // yields a fresh random UUID when the SMBIOS UUID is a placeholder — openframe/docs/agent-openframe-mode.md + var hostUUID string + if c.Bool("openframe-mode") { + identifierPath := filepath.Join(rootDir, constant.OsqueryIdentifierFileName) + switch b, err := os.ReadFile(identifierPath); { + case err == nil: + hostUUID = strings.TrimSpace(string(b)) + case !errors.Is(err, fs.ErrNotExist): + log.Error().Err(err).Str("path", identifierPath).Msg("read osquery identifier file") + } + } + + if hostUUID == "" { + // Use temporary database for UUID query + tmpDBPath := filepath.Join(os.TempDir(), fmt.Sprintf("orbit-uuid-%s", uuid.NewString())) + defer os.RemoveAll(tmpDBPath) - hostUUID, err := getHostUUID(osquerydPath, tmpDBPath) - if err != nil { - return fmt.Errorf("failed to get host UUID: %w", err) + var err error + hostUUID, err = getHostUUID(osquerydPath, tmpDBPath) + if err != nil { + return fmt.Errorf("failed to get host UUID: %w", err) + } } + // <<< OPENFRAME(agent-openframe-mode) if c.Bool("json") { fmt.Printf("{\"uuid\":\"%s\"}\n", hostUUID) @@ -2756,6 +2793,34 @@ var uuidCommand = &cli.Command{ }, } +// >>> OPENFRAME(agent-openframe-mode): write+rename so `orbit uuid` never reads a torn identifier — openframe/docs/agent-openframe-mode.md +func writeOsqueryIdentifierFile(rootDir, identifier string) error { + path := filepath.Join(rootDir, constant.OsqueryIdentifierFileName) + tmp, err := os.CreateTemp(filepath.Dir(path), ".osquery-identifier-*") + if err != nil { + return fmt.Errorf("create temp osquery identifier file: %w", err) + } + tmpPath := tmp.Name() + defer os.Remove(tmpPath) + + if _, err := tmp.WriteString(identifier); err != nil { + tmp.Close() + return fmt.Errorf("write temp osquery identifier file: %w", err) + } + if err := tmp.Close(); err != nil { + return fmt.Errorf("close temp osquery identifier file: %w", err) + } + if err := os.Chmod(tmpPath, constant.DefaultFileMode); err != nil { + return fmt.Errorf("chmod temp osquery identifier file: %w", err) + } + if err := os.Rename(tmpPath, path); err != nil { + return fmt.Errorf("rename osquery identifier file: %w", err) + } + return nil +} + +// <<< OPENFRAME(agent-openframe-mode) + func getHostUUID(osqueryPath string, osqueryDBPath string) (string, error) { // Make sure parent directory exists (`osqueryd -S` doesn't create the parent directories). if err := os.MkdirAll(filepath.Dir(osqueryDBPath), constant.DefaultDirMode); err != nil { diff --git a/orbit/pkg/constant/constant.go b/orbit/pkg/constant/constant.go index c849abdfb8a..7bfa317300c 100644 --- a/orbit/pkg/constant/constant.go +++ b/orbit/pkg/constant/constant.go @@ -23,6 +23,9 @@ const ( OrbitNodeKeyFileName = "secret-orbit-node-key.txt" // HardwareUUIDFileName is the filename on disk where we store the hardware UUID for migration detection HardwareUUIDFileName = "hardware-uuid.txt" + // >>> OPENFRAME(agent-openframe-mode): identifier reported by `orbit uuid` — openframe/docs/agent-openframe-mode.md + OsqueryIdentifierFileName = "osquery-identifier.txt" + // <<< OPENFRAME(agent-openframe-mode) // OrbitEnrollMaxRetries is the max number of retries when doing an enroll request. // We set it to 6 to allow the retry backoff to take effect. OrbitEnrollMaxRetries = 6 diff --git a/server/fleet/api_orbit.go b/server/fleet/api_orbit.go index 8acddec7650..fb4b6368035 100644 --- a/server/fleet/api_orbit.go +++ b/server/fleet/api_orbit.go @@ -28,6 +28,9 @@ type EnrollOrbitRequest struct { // OsqueryIdentifier holds the identifier used by osquery. // If not set, then the hardware UUID is used to match orbit and osquery. OsqueryIdentifier string `json:"osquery_identifier"` + // >>> OPENFRAME(agent-openframe-mode): osquery instance id, diagnostics only — openframe/docs/agent-openframe-mode.md + InstanceID string `json:"instance_id,omitempty"` + // <<< OPENFRAME(agent-openframe-mode) // ComputerName is the device's friendly name (optional). ComputerName string `json:"computer_name"` // HardwareModel is the device's hardware model. diff --git a/server/fleet/orbit.go b/server/fleet/orbit.go index 567455e4167..b7dbf97c646 100644 --- a/server/fleet/orbit.go +++ b/server/fleet/orbit.go @@ -116,6 +116,9 @@ type OrbitHostInfo struct { // // If not set, then the HardwareUUID is used/set as the osquery identifier. OsqueryIdentifier string + // >>> OPENFRAME(agent-openframe-mode): osquery instance id, diagnostics only — openframe/docs/agent-openframe-mode.md + InstanceID string + // <<< OPENFRAME(agent-openframe-mode) // ComputerName is the device's friendly name (optional). ComputerName string // HardwareModel is the device's hardware model. For example: Standard PC (Q35 + ICH9, 2009) diff --git a/server/service/orbit.go b/server/service/orbit.go index 99fbf37d55c..55d86ce4ac9 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -56,6 +56,9 @@ func enrollOrbitEndpoint(ctx context.Context, request interface{}, svc fleet.Ser OsqueryIdentifier: req.OsqueryIdentifier, ComputerName: req.ComputerName, HardwareModel: req.HardwareModel, + // >>> OPENFRAME(agent-openframe-mode): carry osquery's instance id — openframe/docs/agent-openframe-mode.md + InstanceID: req.InstanceID, + // <<< OPENFRAME(agent-openframe-mode) }, req.EnrollSecret, req.EUAToken) if err != nil { return enrollOrbitResponse{fleet.EnrollOrbitResponse{Err: err}}, nil @@ -176,6 +179,12 @@ func (svc *Service) EnrollOrbit(ctx context.Context, hostInfo fleet.OrbitHostInf slog.LevelInfo, ) + // >>> OPENFRAME(agent-openframe-mode): log instance id to tell apart hosts sharing a hardware UUID — openframe/docs/agent-openframe-mode.md + if fleet.IsOpenframeMode() { + logging.WithExtras(ctx, "instance_id", hostInfo.InstanceID) + } + // <<< OPENFRAME(agent-openframe-mode) + secret, err := svc.ds.VerifyEnrollSecret(ctx, enrollSecret) if err != nil { if fleet.IsNotFound(err) {