From 5117ee47da9ea6be51698473f5b09179201eaa38 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Fri, 1 Mar 2024 13:18:12 -0500 Subject: [PATCH] Expose current enrollment status through knapsack; add to checkup (#1632) --- ee/agent/knapsack/knapsack.go | 22 +++++++++++++++++++ ee/agent/types/knapsack.go | 2 ++ ee/agent/types/mocks/knapsack.go | 24 ++++++++++++++++++++ ee/agent/types/status.go | 10 +++++++++ ee/debug/checkups/checkpoint_test.go | 2 ++ ee/debug/checkups/checkups.go | 2 +- ee/debug/checkups/enroll-secret.go | 33 +++++++++++++++------------- ee/debug/checkups/host.go | 1 + 8 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 ee/agent/types/status.go diff --git a/ee/agent/knapsack/knapsack.go b/ee/agent/knapsack/knapsack.go index 31d0163a7..9d5896df4 100644 --- a/ee/agent/knapsack/knapsack.go +++ b/ee/agent/knapsack/knapsack.go @@ -170,3 +170,25 @@ func (k *knapsack) ReadEnrollSecret() (string, error) { return "", errors.New("enroll secret not set") } + +func (k *knapsack) CurrentEnrollmentStatus() (types.EnrollmentStatus, error) { + enrollSecret, err := k.ReadEnrollSecret() + if err != nil || enrollSecret == "" { + return types.NoEnrollmentKey, nil + } + + if k.ConfigStore() == nil { + return types.Unknown, errors.New("no config store in knapsack") + } + + key, err := k.ConfigStore().Get([]byte("nodeKey")) + if err != nil { + return types.Unknown, fmt.Errorf("getting node key from store: %w", err) + } + + if len(key) == 0 { + return types.Unenrolled, nil + } + + return types.Enrolled, nil +} diff --git a/ee/agent/types/knapsack.go b/ee/agent/types/knapsack.go index 672be17fb..51ccd4a51 100644 --- a/ee/agent/types/knapsack.go +++ b/ee/agent/types/knapsack.go @@ -13,4 +13,6 @@ type Knapsack interface { LatestOsquerydPath(ctx context.Context) string // ReadEnrollSecret returns the enroll secret value, checking in various locations. ReadEnrollSecret() (string, error) + // CurrentEnrollmentStatus returns the current enrollment status of the launcher installation + CurrentEnrollmentStatus() (EnrollmentStatus, error) } diff --git a/ee/agent/types/mocks/knapsack.go b/ee/agent/types/mocks/knapsack.go index 8aa88efd2..9d1b279dd 100644 --- a/ee/agent/types/mocks/knapsack.go +++ b/ee/agent/types/mocks/knapsack.go @@ -202,6 +202,30 @@ func (_m *Knapsack) ControlStore() types.GetterSetterDeleterIteratorUpdater { return r0 } +// CurrentEnrollmentStatus provides a mock function with given fields: +func (_m *Knapsack) CurrentEnrollmentStatus() (types.EnrollmentStatus, error) { + ret := _m.Called() + + var r0 types.EnrollmentStatus + var r1 error + if rf, ok := ret.Get(0).(func() (types.EnrollmentStatus, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() types.EnrollmentStatus); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(types.EnrollmentStatus) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Debug provides a mock function with given fields: func (_m *Knapsack) Debug() bool { ret := _m.Called() diff --git a/ee/agent/types/status.go b/ee/agent/types/status.go new file mode 100644 index 000000000..426442168 --- /dev/null +++ b/ee/agent/types/status.go @@ -0,0 +1,10 @@ +package types + +type EnrollmentStatus string + +const ( + NoEnrollmentKey EnrollmentStatus = "no_enrollment_key" + Unenrolled EnrollmentStatus = "unenrolled" + Enrolled EnrollmentStatus = "enrolled" + Unknown EnrollmentStatus = "unknown" +) diff --git a/ee/debug/checkups/checkpoint_test.go b/ee/debug/checkups/checkpoint_test.go index 34ebdcd8c..478d0b40b 100644 --- a/ee/debug/checkups/checkpoint_test.go +++ b/ee/debug/checkups/checkpoint_test.go @@ -6,6 +6,7 @@ import ( "time" storageci "github.com/kolide/launcher/ee/agent/storage/ci" + "github.com/kolide/launcher/ee/agent/types" typesmocks "github.com/kolide/launcher/ee/agent/types/mocks" "github.com/kolide/launcher/pkg/log/multislogger" "github.com/stretchr/testify/require" @@ -29,6 +30,7 @@ func TestInterrupt_Multiple(t *testing.T) { mockKnapsack.On("Autoupdate").Return(true).Maybe() mockKnapsack.On("LatestOsquerydPath").Return("").Maybe() mockKnapsack.On("ServerProvidedDataStore").Return(nil).Maybe() + mockKnapsack.On("CurrentEnrollmentStatus").Return(types.Enrolled, nil).Maybe() checkupLogger := NewCheckupLogger(multislogger.New().Logger, mockKnapsack) mockKnapsack.AssertExpectations(t) diff --git a/ee/debug/checkups/checkups.go b/ee/debug/checkups/checkups.go index 3931cedcb..47a00bf73 100644 --- a/ee/debug/checkups/checkups.go +++ b/ee/debug/checkups/checkups.go @@ -102,7 +102,7 @@ func checkupsFor(k types.Knapsack, target targetBits) []checkupInt { {&BinaryDirectory{}, doctorSupported | flareSupported}, {&launchdCheckup{}, doctorSupported | flareSupported}, {&runtimeCheckup{}, flareSupported}, - {&enrollSecretCheckup{}, doctorSupported | flareSupported}, + {&enrollSecretCheckup{k: k}, doctorSupported | flareSupported}, {&bboltdbCheckup{k: k}, flareSupported}, {&networkCheckup{}, doctorSupported | flareSupported}, {&installCheckup{}, flareSupported}, diff --git a/ee/debug/checkups/enroll-secret.go b/ee/debug/checkups/enroll-secret.go index 88a87d5ca..c9801a4ac 100644 --- a/ee/debug/checkups/enroll-secret.go +++ b/ee/debug/checkups/enroll-secret.go @@ -6,12 +6,14 @@ import ( "fmt" "io" "os" - "runtime" "github.com/golang-jwt/jwt/v5" + "github.com/kolide/launcher/ee/agent/types" + "github.com/kolide/launcher/pkg/launcher" ) type enrollSecretCheckup struct { + k types.Knapsack summary string status Status } @@ -24,9 +26,8 @@ func (c *enrollSecretCheckup) Run(_ context.Context, extraFH io.Writer) error { secretStatus := make(map[string]Status, 0) secretSummary := make(map[string]string, 0) - for _, secretPath := range getSecretPaths() { - // Later on, we want to fall back to the _first_ secrets status. Set it here - + for _, secretPath := range c.getSecretPaths() { + // Later on, we want to fall back to the _first_ secret's status. Set it here st, summary := parseSecret(extraFH, secretPath) secretStatus[secretPath] = st secretSummary[secretPath] = summary @@ -74,19 +75,21 @@ func (c *enrollSecretCheckup) Data() any { return nil } -// getSecretPaths returns potential platform default secret path. It should probably get folded into flags, but I'm not -// quite sure how yet. -func getSecretPaths() []string { - switch runtime.GOOS { - case "darwin": - return []string{"/etc/kolide-k2/secret"} - case "linux": - return []string{"/etc/kolide-k2/secret"} - case "windows": - return []string{"C:\\Program Files\\Kolide\\Launcher-kolide-k2\\conf\\secret"} +// getSecretPaths returns the secret path configured via flags, if available; and the default +// secret path, if available and different from the configured path. +func (c *enrollSecretCheckup) getSecretPaths() []string { + enrollSecretPaths := make([]string, 0) + + if c.k.EnrollSecretPath() != "" { + enrollSecretPaths = append(enrollSecretPaths, c.k.EnrollSecretPath()) } - return nil + defaultPath := launcher.DefaultPath(launcher.SecretFile) + if defaultPath != "" && c.k.EnrollSecretPath() != defaultPath { + enrollSecretPaths = append(enrollSecretPaths, defaultPath) + } + + return enrollSecretPaths } func parseSecret(extraFH io.Writer, secretPath string) (Status, string) { diff --git a/ee/debug/checkups/host.go b/ee/debug/checkups/host.go index b23747431..36525b005 100644 --- a/ee/debug/checkups/host.go +++ b/ee/debug/checkups/host.go @@ -39,6 +39,7 @@ func (hc *hostInfoCheckup) Run(ctx context.Context, extraFH io.Writer) error { hc.data["bbolt_db_size"] = hc.bboltDbSize() desktopProcesses := runner.InstanceDesktopProcessRecords() hc.data["user_desktop_processes"] = desktopProcesses + hc.data["enrollment_status"] = naIfError(hc.k.CurrentEnrollmentStatus()) uptimeRaw, err := host.Uptime() if err != nil {