Skip to content

Commit

Permalink
Add registration ID to osquery history (#1982)
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany authored Dec 9, 2024
1 parent 9818435 commit b36c719
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 35 deletions.
14 changes: 8 additions & 6 deletions ee/debug/checkups/osquery_restarts.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ func (orc *osqRestartCheckup) Run(ctx context.Context, extraFH io.Writer) error

for idx, instance := range restartHistory {
results[idx] = map[string]string{
"start_time": instance.StartTime,
"connect_time": instance.ConnectTime,
"exit_time": instance.ExitTime,
"instance_id": instance.InstanceId,
"version": instance.Version,
"errors": instance.Error,
"registration_id": instance.RegistrationId,
"instance_run_id": instance.RunId,
"start_time": instance.StartTime,
"connect_time": instance.ConnectTime,
"exit_time": instance.ExitTime,
"instance_id": instance.InstanceId,
"version": instance.Version,
"errors": instance.Error,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

func TablePlugin() *table.Plugin {
columns := []table.ColumnDefinition{
table.TextColumn("registration_id"),
table.TextColumn("instance_run_id"),
table.TextColumn("start_time"),
table.TextColumn("connect_time"),
Expand All @@ -33,6 +34,7 @@ func generate() table.GenerateFunc {
for _, instance := range history {

results = append(results, map[string]string{
"registration_id": instance.RegistrationId,
"instance_run_id": instance.RunId,
"start_time": instance.StartTime,
"connect_time": instance.ConnectTime,
Expand Down
28 changes: 23 additions & 5 deletions pkg/osquery/runtime/history/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,30 @@ func LatestInstance() (Instance, error) {
currentHistory.Lock()
defer currentHistory.Unlock()

if currentHistory.instances == nil || len(currentHistory.instances) == 0 {
if len(currentHistory.instances) == 0 {
return Instance{}, NoInstancesError{}
}

return *currentHistory.instances[len(currentHistory.instances)-1], nil
}

func LatestInstanceByRegistrationID(registrationId string) (Instance, error) {
currentHistory.Lock()
defer currentHistory.Unlock()

if len(currentHistory.instances) == 0 {
return Instance{}, NoInstancesError{}
}

for i := len(currentHistory.instances) - 1; i > -1; i -= 1 {
if currentHistory.instances[i].RegistrationId == registrationId {
return *currentHistory.instances[i], nil
}
}

return Instance{}, NoInstancesError{}
}

func LatestInstanceUptimeMinutes() (int64, error) {
lastInstance, err := LatestInstance()
if err != nil {
Expand All @@ -88,7 +105,7 @@ func LatestInstanceUptimeMinutes() (int64, error) {
}

// NewInstance adds a new instance to the osquery instance history and returns it
func NewInstance(runId string) (*Instance, error) {
func NewInstance(registrationId string, runId string) (*Instance, error) {
currentHistory.Lock()
defer currentHistory.Unlock()

Expand All @@ -98,9 +115,10 @@ func NewInstance(runId string) (*Instance, error) {
}

newInstance := &Instance{
RunId: runId,
StartTime: timeNow(),
Hostname: hostname,
RegistrationId: registrationId,
RunId: runId,
StartTime: timeNow(),
Hostname: hostname,
}

currentHistory.addInstanceToHistory(newInstance)
Expand Down
78 changes: 77 additions & 1 deletion pkg/osquery/runtime/history/history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestNewInstance(t *testing.T) { // nolint:paralleltest

require.NoError(t, InitHistory(setupStorage(t, tt.initialInstances...)))

_, err := NewInstance(ulid.New())
_, err := NewInstance(ulid.New(), ulid.New())

assert.Equal(t, tt.wantNumInstances, len(currentHistory.instances), "expect history length to reflect new instance")

Expand Down Expand Up @@ -176,6 +176,82 @@ func TestLatestInstance(t *testing.T) { // nolint:paralleltest
}
}

func TestLatestInstanceForRegistrationID(t *testing.T) { // nolint:paralleltest
tests := []struct {
name string
registrationID string
initialInstances []*Instance
want Instance
errString string
}{
{
name: "success",
registrationID: "test",
initialInstances: []*Instance{
{
StartTime: "first_expected_start_time",
RegistrationId: "some other",
},
{
StartTime: "second_expected_start_time",
RegistrationId: "test",
},
{
StartTime: "third_expected_start_time",
RegistrationId: "test",
},
{
StartTime: "fourth_expected_start_time",
RegistrationId: "another",
},
},
want: Instance{
StartTime: "third_expected_start_time",
RegistrationId: "test",
},
},
{
name: "no_instances_error",
registrationID: "test",
errString: NoInstancesError{}.Error(),
},
{
name: "no matching instances",
registrationID: "test3",
initialInstances: []*Instance{
{
StartTime: "first_expected_start_time",
RegistrationId: "test",
},
{
StartTime: "second_expected_start_time",
RegistrationId: "test1",
},
{
StartTime: "third_expected_start_time",
RegistrationId: "test2",
},
},
errString: NoInstancesError{}.Error(),
},
}
for _, tt := range tests { // nolint:paralleltest
t.Run(tt.name, func(t *testing.T) {
t.Cleanup(func() { currentHistory = &History{} })

require.NoError(t, InitHistory(setupStorage(t, tt.initialInstances...)))

got, err := LatestInstanceByRegistrationID(tt.registrationID)

if tt.errString != "" {
assert.EqualError(t, err, tt.errString)
}

assert.Equal(t, tt.want, got)
})
}
}

func TestLatestInstanceUptimeMinutes(t *testing.T) { // nolint:paralleltest
tests := []struct {
name string
Expand Down
17 changes: 9 additions & 8 deletions pkg/osquery/runtime/history/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import (
)

type Instance struct {
RunId string // ID for instance, assigned by launcher
StartTime string
ConnectTime string
ExitTime string
Hostname string
InstanceId string // ID from osquery
Version string
Error string
RegistrationId string // which registration this instance belongs to
RunId string // ID for instance, assigned by launcher
StartTime string
ConnectTime string
ExitTime string
Hostname string
InstanceId string // ID from osquery
Version string
Error string
}

type Querier interface {
Expand Down
2 changes: 1 addition & 1 deletion pkg/osquery/runtime/osqueryinstance.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ func (i *OsqueryInstance) Launch() error {
"osquery socket created",
)

stats, err := history.NewInstance(i.runId)
stats, err := history.NewInstance(i.registrationId, i.runId)
if err != nil {
i.slogger.Log(ctx, slog.LevelWarn,
"could not create new osquery instance history",
Expand Down
26 changes: 14 additions & 12 deletions pkg/osquery/table/launcher_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@ import (
"github.com/osquery/osquery-go/plugin/table"
)

func LauncherConfigTable(store types.Getter) *table.Plugin {
func LauncherConfigTable(store types.Getter, registrationTracker types.RegistrationTracker) *table.Plugin {
columns := []table.ColumnDefinition{
table.TextColumn("config"),
table.TextColumn("registration_id"),
}
return table.NewPlugin("kolide_launcher_config", columns, generateLauncherConfig(store))
return table.NewPlugin("kolide_launcher_config", columns, generateLauncherConfig(store, registrationTracker))
}

func generateLauncherConfig(store types.Getter) table.GenerateFunc {
func generateLauncherConfig(store types.Getter, registrationTracker types.RegistrationTracker) table.GenerateFunc {
return func(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
config, err := osquery.Config(store)
if err != nil {
return nil, err
results := make([]map[string]string, 0)
for _, registrationId := range registrationTracker.RegistrationIDs() {
config, err := osquery.Config(store)
if err != nil {
return nil, err
}
results = append(results, map[string]string{
"config": config,
"registration_id": registrationId,
})
}
results := []map[string]string{
{
"config": config,
},
}

return results, nil
}
}
4 changes: 3 additions & 1 deletion pkg/osquery/table/launcher_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func LauncherInfoTable(configStore types.GetterSetter, LauncherHistoryStore type
table.TextColumn("revision"),
table.TextColumn("version"),
table.TextColumn("version_chain"),
table.TextColumn("registration_id"),
table.TextColumn("identifier"),
table.TextColumn("osquery_instance_id"),
table.TextColumn("uptime"),
Expand Down Expand Up @@ -57,7 +58,7 @@ func generateLauncherInfoTable(configStore types.GetterSetter, LauncherHistorySt
return nil, err
}

osqueryInstance, err := history.LatestInstance()
osqueryInstance, err := history.LatestInstanceByRegistrationID(types.DefaultRegistrationID)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -91,6 +92,7 @@ func generateLauncherInfoTable(configStore types.GetterSetter, LauncherHistorySt
"revision": version.Version().Revision,
"version": version.Version().Version,
"version_chain": os.Getenv("KOLIDE_LAUNCHER_VERSION_CHAIN"),
"registration_id": types.DefaultRegistrationID,
"identifier": identifier,
"osquery_instance_id": osqueryInstance.InstanceId,
"fingerprint": fingerprint,
Expand Down
2 changes: 1 addition & 1 deletion pkg/osquery/table/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
// around _launcher_ things thus do not make sense in tables.ext
func LauncherTables(k types.Knapsack) []osquery.OsqueryPlugin {
return []osquery.OsqueryPlugin{
LauncherConfigTable(k.ConfigStore()),
LauncherConfigTable(k.ConfigStore(), k),
LauncherDbInfo(k.BboltDB()),
LauncherInfoTable(k.ConfigStore(), k.LauncherHistoryStore()),
launcher_db.TablePlugin("kolide_server_data", k.ServerProvidedDataStore()),
Expand Down

0 comments on commit b36c719

Please sign in to comment.