fleet/orbit/pkg/update/notifications.go

644 lines
22 KiB
Go
Raw Normal View History

package update
import (
"errors"
"runtime"
"sync"
"sync/atomic"
"time"
"github.com/fleetdm/fleet/v4/orbit/pkg/bitlocker"
"github.com/fleetdm/fleet/v4/orbit/pkg/profiles"
"github.com/fleetdm/fleet/v4/orbit/pkg/scripts"
fleetscripts "github.com/fleetdm/fleet/v4/pkg/scripts"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/rs/zerolog/log"
)
type runCmdFunc func() error
type checkEnrollmentFunc func() (bool, string, error)
type checkAssignedEnrollmentProfileFunc func(url string) error
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
// renewEnrollmentProfileConfigReceiver is a kind of middleware that wraps an
// OrbitConfigFetcher and detects if the fleet server sent a notification to
// renew the enrollment profile. If so, it runs the command (as root) to
// bootstrap the renewal of the profile on the device (the user still needs to
// execute some manual steps to accept the new profile).
//
// It ensures only one renewal command is executed at any given time, and that
// it doesn't re-execute the command until a certain amount of time has passed.
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
type renewEnrollmentProfileConfigReceiver struct {
// Frequency is the minimum amount of time that must pass between two
// executions of the profile renewal command.
Frequency time.Duration
// for tests, to be able to mock command execution. If nil, will use
// runRenewEnrollmentProfile.
runCmdFn runCmdFunc
// for tests, to be able to mock the function that checks for Fleet
// enrollment
checkEnrollmentFn checkEnrollmentFunc
// for tests, to be able to mock the function that checks for the assigned enrollment profile
checkAssignedEnrollmentProfileFn checkAssignedEnrollmentProfileFunc
// ensures only one command runs at a time, protects access to lastRun
cmdMu sync.Mutex
lastRun time.Time
fleetURL string
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func ApplyRenewEnrollmentProfileConfigFetcherMiddleware(fetcher OrbitConfigFetcher, frequency time.Duration, fleetURL string) fleet.OrbitConfigReceiver {
return &renewEnrollmentProfileConfigReceiver{Frequency: frequency, fleetURL: fleetURL}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (h *renewEnrollmentProfileConfigReceiver) Run(config *fleet.OrbitConfig) error {
if config.Notifications.RenewEnrollmentProfile {
if h.cmdMu.TryLock() {
defer h.cmdMu.Unlock()
// Note that the macOS notification popup will be shown periodically
// until the Fleet server gets notified that the device is now properly
// enrolled (after the user's manual steps, and osquery reporting the
// updated mdm enrollment).
// See https://github.com/fleetdm/fleet/pull/9409#discussion_r1084382455
if time.Since(h.lastRun) >= h.Frequency {
// we perform this check locally on the client too to avoid showing the
// dialog if the client is enrolled to an MDM server.
enrollFn := h.checkEnrollmentFn
if enrollFn == nil {
enrollFn = profiles.IsEnrolledInMDM
}
enrolled, mdmServerURL, err := enrollFn()
if err != nil {
log.Error().Err(err).Msg("fetching enrollment status")
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
if enrolled {
log.Info().Msgf("a request to renew the enrollment profile was processed but not executed because the host is enrolled into an MDM server with URL: %s", mdmServerURL)
h.lastRun = time.Now().Add(-h.Frequency).Add(2 * time.Minute)
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
// we perform this check locally on the client too to avoid showing the
// dialog if the Fleet enrollment profile has not been assigned to the device in
// Apple Business Manager.
assignedFn := h.checkAssignedEnrollmentProfileFn
if assignedFn == nil {
assignedFn = profiles.CheckAssignedEnrollmentProfile
}
if err := assignedFn(h.fleetURL); err != nil {
log.Error().Err(err).Msg("checking assigned enrollment profile")
log.Info().Msg("a request to renew the enrollment profile was processed but not executed because there was an error checking the assigned enrollment profile.")
// TODO: Design a better way to backoff `profiles show` so that the device doesn't get rate
// limited by Apple. For now, wait at least 2 minutes before retrying.
h.lastRun = time.Now().Add(-h.Frequency).Add(2 * time.Minute)
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
fn := h.runCmdFn
if fn == nil {
fn = runRenewEnrollmentProfile
}
if err := fn(); err != nil {
log.Info().Err(err).Msg("calling /usr/bin/profiles to renew enrollment profile failed")
// TODO: Design a better way to backoff `profiles show` so that the device doesn't get rate
// limited by Apple. For now, wait at least 2 minutes before retrying.
h.lastRun = time.Now().Add(-h.Frequency).Add(2 * time.Minute)
return nil
}
h.lastRun = time.Now()
log.Info().Msg("successfully called /usr/bin/profiles to renew enrollment profile")
} else {
log.Debug().Msg("skipped calling /usr/bin/profiles to renew enrollment profile, last run was too recent")
}
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
type execWinAPIFunc func(WindowsMDMEnrollmentArgs) error
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
type windowsMDMEnrollmentConfigReceiver struct {
// Frequency is the minimum amount of time that must pass between two
// executions of the windows MDM enrollment attempt.
Frequency time.Duration
// HostUUID is the current host's UUID.
HostUUID string
// OrbitNodeKey is the current host's orbit node key.
nodeKeyGetter OrbitNodeKeyGetter
// for tests, to be able to mock API commands. If nil, will use
// RunWindowsMDMEnrollment and RunWindowsMDMUnenrollment respectively.
execEnrollFn execWinAPIFunc
execUnenrollFn execWinAPIFunc
// ensures only one command runs at a time, protects access to lastXxxRun and
// isWindowsServer.
mu sync.Mutex
lastEnrollRun time.Time
lastUnenrollRun time.Time
isWindowsServer bool
}
type OrbitNodeKeyGetter interface {
GetNodeKey() (string, error)
}
func ApplyWindowsMDMEnrollmentFetcherMiddleware(
frequency time.Duration,
hostUUID string,
nodeKeyGetter OrbitNodeKeyGetter,
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
) fleet.OrbitConfigReceiver {
return &windowsMDMEnrollmentConfigReceiver{
Frequency: frequency,
HostUUID: hostUUID,
nodeKeyGetter: nodeKeyGetter,
}
}
var errIsWindowsServer = errors.New("device is a Windows Server")
// GetConfig calls the wrapped Fetcher's GetConfig method, and if the fleet
// server set the "needs windows enrollment" flag to true, executes the command
// to enroll into Windows MDM (or not, if the device is a Windows Server).
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMEnrollmentConfigReceiver) Run(cfg *fleet.OrbitConfig) error {
if cfg.Notifications.NeedsProgrammaticWindowsMDMEnrollment {
w.attemptEnrollment(cfg.Notifications)
} else if cfg.Notifications.NeedsProgrammaticWindowsMDMUnenrollment {
w.attemptUnenrollment()
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMEnrollmentConfigReceiver) attemptEnrollment(notifs fleet.OrbitConfigNotifications) {
if notifs.WindowsMDMDiscoveryEndpoint == "" {
log.Info().Err(errors.New("discovery endpoint is missing")).Msg("skipping enrollment, discovery endpoint is empty")
return
}
if w.mu.TryLock() {
defer w.mu.Unlock()
// do not enroll Windows Servers, and do not attempt enrollment if the last
// run is not at least Frequency ago.
if w.isWindowsServer {
log.Debug().Msg("skipped calling RegisterDeviceWithManagement to enroll Windows device, device is a server")
return
}
if time.Since(w.lastEnrollRun) <= w.Frequency {
log.Debug().Msg("skipped calling RegisterDeviceWithManagement to enroll Windows device, last run was too recent")
return
}
nodeKey, err := w.nodeKeyGetter.GetNodeKey()
if err != nil {
log.Info().Err(err).Msg("failed to get orbit node key to enroll Windows device")
return
}
fn := w.execEnrollFn
if fn == nil {
fn = RunWindowsMDMEnrollment
}
args := WindowsMDMEnrollmentArgs{
DiscoveryURL: notifs.WindowsMDMDiscoveryEndpoint,
HostUUID: w.HostUUID,
OrbitNodeKey: nodeKey,
}
if err := fn(args); err != nil {
if errors.Is(err, errIsWindowsServer) {
w.isWindowsServer = true
log.Info().Msg("device is a Windows Server, skipping enrollment")
} else {
log.Info().Err(err).Msg("calling RegisterDeviceWithManagement to enroll Windows device failed")
}
return
}
w.lastEnrollRun = time.Now()
log.Info().Msg("successfully called RegisterDeviceWithManagement to enroll Windows device")
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMEnrollmentConfigReceiver) attemptUnenrollment() {
if w.mu.TryLock() {
defer w.mu.Unlock()
// do not unenroll Windows Servers, and do not attempt unenrollment if the
// last run is not at least Frequency ago.
if w.isWindowsServer {
log.Debug().Msg("skipped calling UnregisterDeviceWithManagement to unenroll Windows device, device is a server")
return
}
if time.Since(w.lastUnenrollRun) <= w.Frequency {
log.Debug().Msg("skipped calling UnregisterDeviceWithManagement to unenroll Windows device, last run was too recent")
return
}
fn := w.execUnenrollFn
if fn == nil {
fn = RunWindowsMDMUnenrollment
}
// NOTE: args is actually unused by unenrollment, it is just for the
// function signature consistency.
args := WindowsMDMEnrollmentArgs{}
if err := fn(args); err != nil {
if errors.Is(err, errIsWindowsServer) {
w.isWindowsServer = true
log.Info().Msg("device is a Windows Server, skipping unenrollment")
} else {
log.Info().Err(err).Msg("calling UnregisterDeviceWithManagement to unenroll Windows device failed")
}
return
}
w.lastUnenrollRun = time.Now()
log.Info().Msg("successfully called UnregisterDeviceWithManagement to unenroll Windows device")
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
type runScriptsConfigReceiver struct {
// ScriptsExecutionEnabled indicates if this agent allows scripts execution.
// If it doesn't, scripts are not executed, but a response is returned to the
// Fleet server so it knows the agent processed the request. Note that this
// should be set to the value of the --scripts-enabled command-line flag. An
// additional, dynamic check is done automatically by the
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
// runScriptsConfigReceiver if this field is false to get the value from the
// MDM configuration profile.
ScriptsExecutionEnabled bool
// ScriptsClient is the client to use to fetch the script to execute and save
// back its results.
ScriptsClient scripts.Client
// the dynamic scripts enabled check is done to check via mdm configuration
// profile if the host is allowed to run dynamic scripts. It is only done
// on macos and only if ScriptsExecutionEnabled is false.
dynamicScriptsEnabled atomic.Bool
dynamicScriptsEnabledCheckInterval time.Duration
// for tests, if set will use this instead of profiles.GetFleetdConfig.
testGetFleetdConfig func() (*fleet.MDMAppleFleetdConfig, error)
// for tests, to be able to mock command execution. If nil, will use
// (scripts.Runner{...}).Run. To help with testing, the function receives as
// argument the scripts.Runner value that would've executed the call.
runScriptsFn func(*scripts.Runner, []string) error
// ensures only one script execution runs at a time
mu sync.Mutex
rootDirPath string
}
Added orbit_version, fleet_desktop_version, and scripts_enabled to host details. (#18123) #17361 #17148 In GET fleet/hosts/:id response, added the following fields: - orbit_version - `orbit_version == null` means this agent is not an orbit agent - fleet_desktop_version - `fleet_desktop_version == null` means this agent is not an orbit agent or it is an older version which is not collecting the desktop version - `fleet_desktop_version == ""` means this agent is an orbit agent but does not have fleet desktop - scripts_enabled - `scripts_enabled == null` means this agent is not an orbit agent or it is an older version which is not collecting scripts_enabled In orbit_info table, added the following fields: - desktop_version - scripts_enabled Updated docs for orbit_info PR: https://github.com/fleetdm/fleet/pull/18135 Updated API docs: https://github.com/fleetdm/fleet/pull/17814 MDM lock/unlock/wipe error messages are not part of this PR. They will be in a separate PR. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features. - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-04-09 21:33:44 +00:00
func ApplyRunScriptsConfigFetcherMiddleware(
scriptsEnabled bool, scriptsClient scripts.Client, rootDirPath string,
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
) (fleet.OrbitConfigReceiver, func() bool) {
scriptsFetcher := &runScriptsConfigReceiver{
ScriptsExecutionEnabled: scriptsEnabled,
ScriptsClient: scriptsClient,
dynamicScriptsEnabledCheckInterval: 5 * time.Minute,
rootDirPath: rootDirPath,
}
// start the dynamic check for scripts enabled if required
scriptsFetcher.runDynamicScriptsEnabledCheck()
Added orbit_version, fleet_desktop_version, and scripts_enabled to host details. (#18123) #17361 #17148 In GET fleet/hosts/:id response, added the following fields: - orbit_version - `orbit_version == null` means this agent is not an orbit agent - fleet_desktop_version - `fleet_desktop_version == null` means this agent is not an orbit agent or it is an older version which is not collecting the desktop version - `fleet_desktop_version == ""` means this agent is an orbit agent but does not have fleet desktop - scripts_enabled - `scripts_enabled == null` means this agent is not an orbit agent or it is an older version which is not collecting scripts_enabled In orbit_info table, added the following fields: - desktop_version - scripts_enabled Updated docs for orbit_info PR: https://github.com/fleetdm/fleet/pull/18135 Updated API docs: https://github.com/fleetdm/fleet/pull/17814 MDM lock/unlock/wipe error messages are not part of this PR. They will be in a separate PR. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features. - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-04-09 21:33:44 +00:00
return scriptsFetcher, scriptsFetcher.scriptsEnabled
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (h *runScriptsConfigReceiver) runDynamicScriptsEnabledCheck() {
getFleetdConfig := h.testGetFleetdConfig
if getFleetdConfig == nil {
getFleetdConfig = profiles.GetFleetdConfig
}
// only run on macos and only if scripts are disabled by default for the
// agent (but always run if a test get fleetd config function is set).
if (runtime.GOOS == "darwin" && !h.ScriptsExecutionEnabled) || (h.testGetFleetdConfig != nil) {
go func() {
runCheck := func() {
cfg, err := getFleetdConfig()
if err != nil {
if err != profiles.ErrNotImplemented {
// note that an unenrolled host will not return an error, it will
// return the zero-value struct, so this logging should not be too
// noisy unless something goes wrong.
log.Info().Err(err).Msg("get fleetd configuration failed")
}
return
}
h.dynamicScriptsEnabled.Store(cfg.EnableScripts)
}
// check immediately at startup, before checking at the interval
runCheck()
// check every minute
for range time.Tick(h.dynamicScriptsEnabledCheckInterval) {
runCheck()
}
}()
}
}
// GetConfig calls the wrapped Fetcher's GetConfig method, and if the fleet
// server sent a list of scripts to execute, starts a goroutine to execute
// them.
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (h *runScriptsConfigReceiver) Run(cfg *fleet.OrbitConfig) error {
timeout := fleetscripts.MaxHostExecutionTime
if cfg.ScriptExeTimeout > 0 {
timeout = time.Duration(cfg.ScriptExeTimeout) * time.Second
}
if runtime.GOOS == "darwin" {
if cfg.Notifications.RunSetupExperience && !CanRun(h.rootDirPath, "swiftDialog", SwiftDialogMacOSTarget) {
log.Debug().Msg("exiting scripts config runner early during setup experience: swiftDialog is not installed")
return nil
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
if len(cfg.Notifications.PendingScriptExecutionIDs) > 0 {
if h.mu.TryLock() {
log.Debug().Msgf("received request to run scripts %v", cfg.Notifications.PendingScriptExecutionIDs)
runner := &scripts.Runner{
Added orbit_version, fleet_desktop_version, and scripts_enabled to host details. (#18123) #17361 #17148 In GET fleet/hosts/:id response, added the following fields: - orbit_version - `orbit_version == null` means this agent is not an orbit agent - fleet_desktop_version - `fleet_desktop_version == null` means this agent is not an orbit agent or it is an older version which is not collecting the desktop version - `fleet_desktop_version == ""` means this agent is an orbit agent but does not have fleet desktop - scripts_enabled - `scripts_enabled == null` means this agent is not an orbit agent or it is an older version which is not collecting scripts_enabled In orbit_info table, added the following fields: - desktop_version - scripts_enabled Updated docs for orbit_info PR: https://github.com/fleetdm/fleet/pull/18135 Updated API docs: https://github.com/fleetdm/fleet/pull/17814 MDM lock/unlock/wipe error messages are not part of this PR. They will be in a separate PR. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features. - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-04-09 21:33:44 +00:00
ScriptExecutionEnabled: h.scriptsEnabled(),
Client: h.ScriptsClient,
ScriptExecutionTimeout: timeout,
}
fn := runner.Run
if h.runScriptsFn != nil {
fn = func(execIDs []string) error {
return h.runScriptsFn(runner, execIDs)
}
}
go func() {
defer h.mu.Unlock()
if err := fn(cfg.Notifications.PendingScriptExecutionIDs); err != nil {
log.Info().Err(err).Msg("running scripts failed")
return
}
log.Debug().Msgf("running scripts %v succeeded", cfg.Notifications.PendingScriptExecutionIDs)
}()
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (h *runScriptsConfigReceiver) scriptsEnabled() bool {
Added orbit_version, fleet_desktop_version, and scripts_enabled to host details. (#18123) #17361 #17148 In GET fleet/hosts/:id response, added the following fields: - orbit_version - `orbit_version == null` means this agent is not an orbit agent - fleet_desktop_version - `fleet_desktop_version == null` means this agent is not an orbit agent or it is an older version which is not collecting the desktop version - `fleet_desktop_version == ""` means this agent is an orbit agent but does not have fleet desktop - scripts_enabled - `scripts_enabled == null` means this agent is not an orbit agent or it is an older version which is not collecting scripts_enabled In orbit_info table, added the following fields: - desktop_version - scripts_enabled Updated docs for orbit_info PR: https://github.com/fleetdm/fleet/pull/18135 Updated API docs: https://github.com/fleetdm/fleet/pull/17814 MDM lock/unlock/wipe error messages are not part of this PR. They will be in a separate PR. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features. - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-04-09 21:33:44 +00:00
// scripts are always enabled if the agent is started with the
// --scripts-enabled flag. If it is not started with this flag, then
// scripts are enabled only if the mdm profile says so.
return h.ScriptsExecutionEnabled || h.dynamicScriptsEnabled.Load()
}
type DiskEncryptionKeySetter interface {
SetOrUpdateDiskEncryptionKey(diskEncryptionStatus fleet.OrbitHostDiskEncryptionKeyPayload) error
}
// execEncryptVolumeFunc handles the encryption of a volume identified by its
// string identifier (e.g., "C:").
//
// It returns a string representing the recovery key and an error if any occurs during the process.
type execEncryptVolumeFunc func(volumeID string) (recoveryKey string, err error)
// execGetEncryptionStatusFunc retrieves the encryption status of all volumes
// managed by Bitlocker.
//
// It returns a slice of bitlocker.VolumeStatus, each representing the
// encryption status of a volume, and an error if the operation fails.
type execGetEncryptionStatusFunc func() (status []bitlocker.VolumeStatus, err error)
// execDecryptVolumeFunc handles the decryption of a volume identified by its
// string identifier (e.g., "C:")
//
// It returns an error if the process fails.
type execDecryptVolumeFunc func(volumeID string) error
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
type windowsMDMBitlockerConfigReceiver struct {
// Frequency is the minimum amount of time that must pass between two
// executions of the windows MDM enrollment attempt.
Frequency time.Duration
// Bitlocker Operation Results
EncryptionResult DiskEncryptionKeySetter
// tracks last time a disk encryption has successfully run
lastRun time.Time
// ensures only one script execution runs at a time
mu sync.Mutex
// for tests, to be able to mock API commands. If nil, will use
// bitlocker.EncryptVolume
execEncryptVolumeFn execEncryptVolumeFunc
// for tests, to be able to mock API commands. If nil, will use
// bitlocker.GetEncryptionStatus
execGetEncryptionStatusFn execGetEncryptionStatusFunc
// for tests, to be able to mock the decryption process. If nil, will use
// bitlocker.DecryptVolume
execDecryptVolumeFn execDecryptVolumeFunc
}
func ApplyWindowsMDMBitlockerFetcherMiddleware(
frequency time.Duration,
encryptionResult DiskEncryptionKeySetter,
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
) fleet.OrbitConfigReceiver {
return &windowsMDMBitlockerConfigReceiver{
Frequency: frequency,
EncryptionResult: encryptionResult,
}
}
// GetConfig calls the wrapped Fetcher's GetConfig method, and if the fleet
// server set the "EnforceBitLockerEncryption" flag to true, executes the command
// to attempt BitlockerEncryption (or not, if the device is a Windows Server).
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) Run(cfg *fleet.OrbitConfig) error {
if cfg.Notifications.EnforceBitLockerEncryption {
if w.mu.TryLock() {
defer w.mu.Unlock()
w.attemptBitlockerEncryption(cfg.Notifications)
}
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
return nil
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) attemptBitlockerEncryption(notifs fleet.OrbitConfigNotifications) {
if time.Since(w.lastRun) <= w.Frequency {
log.Debug().Msg("skipped encryption process, last run was too recent")
return
}
// Windows servers are not supported. Check and skip if that's the case.
if isServer, err := IsRunningOnWindowsServer(); isServer || err != nil {
if err != nil {
log.Error().Err(err).Msg("checking if the host is a Windows server")
} else {
log.Debug().Msg("device is a Windows Server, encryption is not going to be performed")
}
return
}
const targetVolume = "C:"
encryptionStatus, err := w.getEncryptionStatusForVolume(targetVolume)
if err != nil {
log.Debug().Err(err).Msgf("unable to get encryption status for target volume %s, continuing anyway", targetVolume)
}
// don't do anything if the disk is being encrypted/decrypted
if w.bitLockerActionInProgress(encryptionStatus) {
log.Debug().Msgf("skipping encryption as the disk is not available. Disk conversion status: %d", encryptionStatus.ConversionStatus)
return
}
// if the disk is encrypted, try to decrypt it first.
if encryptionStatus != nil &&
encryptionStatus.ConversionStatus == bitlocker.ConversionStatusFullyEncrypted {
log.Debug().Msg("disk was previously encrypted. Attempting to decrypt it")
if err := w.decryptVolume(targetVolume); err != nil {
log.Error().Err(err).Msg("decryption failed")
if serverErr := w.updateFleetServer("", err); serverErr != nil {
log.Error().Err(serverErr).Msg("failed to send decryption failure to Fleet Server")
return
}
}
// return regardless of the operation output.
//
// the decryption process takes an unknown amount of time (depending on
// factors outside of our control) and the next tick will be a noop if the
// disk is not ready to be encrypted yet (due to the
// w.bitLockerActionInProgress check above)
return
}
recoveryKey, encryptionErr := w.performEncryption(targetVolume)
// before reporting the error to the server, check if the error we've got is valid.
// see the description of w.isMisreportedDecryptionError and issue #15916.
var pErr *bitlocker.EncryptionError
if errors.As(encryptionErr, &pErr) && w.isMisreportedDecryptionError(pErr, encryptionStatus) {
log.Error().Msg("disk encryption failed due to previous unsuccessful attempt, user action required")
return
}
if serverErr := w.updateFleetServer(recoveryKey, encryptionErr); serverErr != nil {
log.Error().Err(serverErr).Msg("failed to send encryption result to Fleet Server")
return
}
if encryptionErr != nil {
log.Error().Err(err).Msg("failed to encrypt the volume")
return
}
w.lastRun = time.Now()
}
// getEncryptionStatusForVolume retrieves the encryption status for a specific volume.
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) getEncryptionStatusForVolume(volume string) (*bitlocker.EncryptionStatus, error) {
fn := w.execGetEncryptionStatusFn
if fn == nil {
fn = bitlocker.GetEncryptionStatus
}
status, err := fn()
if err != nil {
return nil, err
}
for _, s := range status {
if s.DriveVolume == volume {
return s.Status, nil
}
}
return nil, nil
}
// bitLockerActionInProgress determines an encryption/decription action is in
// progress based on the reported status.
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) bitLockerActionInProgress(status *bitlocker.EncryptionStatus) bool {
if status == nil {
return false
}
// Check if the status matches any of the specified conditions
return status.ConversionStatus == bitlocker.ConversionStatusDecryptionInProgress ||
status.ConversionStatus == bitlocker.ConversionStatusDecryptionPaused ||
status.ConversionStatus == bitlocker.ConversionStatusEncryptionInProgress ||
status.ConversionStatus == bitlocker.ConversionStatusEncryptionPaused
}
// performEncryption executes the encryption process.
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) performEncryption(volume string) (string, error) {
fn := w.execEncryptVolumeFn
if fn == nil {
fn = bitlocker.EncryptVolume
}
recoveryKey, err := fn(volume)
if err != nil {
return "", err
}
return recoveryKey, nil
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) decryptVolume(targetVolume string) error {
fn := w.execDecryptVolumeFn
if fn == nil {
fn = bitlocker.DecryptVolume
}
return fn(targetVolume)
}
// isMisreportedDecryptionError checks whether the given error is a potentially
// misreported decryption error.
//
// It addresses cases where a previous encryption attempt failed due to other
// errors but subsequent attempts to encrypt the disk could erroneously return
// a bitlocker.FVE_E_NOT_DECRYPTED error.
//
// This function checks if the disk is actually fully decrypted
// (status.ConversionStatus == bitlocker.CONVERSION_STATUS_FULLY_DECRYPTED) and
// whether the reported error is bitlocker.FVE_E_NOT_DECRYPTED. If these
// conditions are met, the error is not accurately reflecting the disk's actual
// encryption state.
//
// For more context, see issue #15916
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) isMisreportedDecryptionError(err *bitlocker.EncryptionError, status *bitlocker.EncryptionStatus) bool {
return err.Code() == bitlocker.ErrorCodeNotDecrypted &&
status != nil &&
status.ConversionStatus == bitlocker.ConversionStatusFullyDecrypted
}
Orbit config receiver (#18518) New interface for adding periodic jobs that rely on notifications/config changes in Orbit. Previously if we wanted to have recurring checks in Orbit, we would add them into a chain of `GetConfig` calls. This call chain would be run periodically by one of the runners registered with the cli application framework. The new method to register `OrbitConfigReceivers` with the `OrbitClient`, and then register the orbit client itself with the application framework. Instead of having giving each fetcher an internal reference to the previous fetcher that it must call, the receiver is registered with the client and the new config is passed to the receiver. This is the old `GetConfig()` interface: ```go type OrbitConfigFetcher interface { GetConfig() (*fleet.OrbitConfig, error) } ``` This is the new `OrbitConfigReceiver` interface: ```go type OrbitConfigReceiver interface { Run(*OrbitConfig) error } ``` To register a new receiver, you call the `RegisterConfigReceiver` method on the client. ```go orbitClient.RegisterConfigReceiver(extRunner) ``` Downsides of the old method: - Spaghetti call chain setup - Cascading failure, of one fails, all after it fail - Run in series, one long function call holds up the rest - Anything that wants to restart orbit is added as a Runner to the application, meaning there could be several timers calling `GetConfig` and running the chain Benefits of the new method: - Clean `RegisterConfigReceiver` api, no call chaining required - Config receivers can be added at runtime - Isolated receivers, one failing call don't effect others - All calls are run in parallel in goroutines, no calls can hold up the rest - No more need for multiple runners, using a context cancel, any receiver can queue a call to restart orbit - Single point to handle errors and logging for all receivers - Panic recovery to stop orbit from crashing - Easier to test, configs are passed in and do not require a call chain This branch contains a little bit of code from the installer method I was working on because I branched it off of that. (oops) Not all code comments surrounding old `GetConfig()` methods have been fully updated yet Possible changes: - Update the interface to take a context, so we can let receivers know to exit early. I can imagine two cases for this: - The application is about to restart - We can set a timeout for how long receivers are allowed to take Closes #12662 --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-05-09 19:22:56 +00:00
func (w *windowsMDMBitlockerConfigReceiver) updateFleetServer(key string, err error) error {
// Getting Bitlocker encryption operation error message if any
// This is going to be sent to Fleet Server
bitlockerError := ""
if err != nil {
bitlockerError = err.Error()
}
// Update Fleet Server with encryption result
payload := fleet.OrbitHostDiskEncryptionKeyPayload{
EncryptionKey: []byte(key),
ClientError: bitlockerError,
}
return w.EncryptionResult.SetOrUpdateDiskEncryptionKey(payload)
}