Skip to content

Commit

Permalink
[TUF] If a downgrade occurs, restart the given binary (#1411)
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany authored Oct 18, 2023
1 parent 705352f commit 1ac7d3e
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 69 deletions.
6 changes: 6 additions & 0 deletions pkg/agent/flags/flag_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,9 @@ func (fc *FlagController) OsqueryHealthcheckStartupDelay() time.Duration {
WithMax(1*time.Hour),
).get(fc.getControlServerValue(keys.OsqueryHealthcheckStartupDelay))
}

func (fc *FlagController) LocalDevelopmentPath() string {
return NewStringFlagValue(
WithDefaultString(fc.cmdLineOpts.LocalDevelopmentPath),
).get(nil)
}
1 change: 1 addition & 0 deletions pkg/agent/flags/keys/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const (
TraceIngestServerURL FlagKey = "trace_ingest_url"
DisableTraceIngestTLS FlagKey = "disable_trace_ingest_tls"
InModernStandby FlagKey = "in_modern_standby"
LocalDevelopmentPath FlagKey = "localdev_path"
)

func (key FlagKey) String() string {
Expand Down
4 changes: 4 additions & 0 deletions pkg/agent/knapsack/knapsack.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,7 @@ func (k *knapsack) SetOsqueryHealthcheckStartupDelay(delay time.Duration) error
func (k *knapsack) OsqueryHealthcheckStartupDelay() time.Duration {
return k.flags.OsqueryHealthcheckStartupDelay()
}

func (k *knapsack) LocalDevelopmentPath() string {
return k.flags.LocalDevelopmentPath()
}
3 changes: 3 additions & 0 deletions pkg/agent/types/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,7 @@ type Flags interface {
// OsqueryHealthcheckStartupDelay is the time to wait before beginning osquery healthchecks
SetOsqueryHealthcheckStartupDelay(delay time.Duration) error
OsqueryHealthcheckStartupDelay() time.Duration

// LocalDevelopmentPath points to a local build of launcher to use instead of the one selected from the autoupdate library
LocalDevelopmentPath() string
}
25 changes: 20 additions & 5 deletions pkg/agent/types/mocks/flags.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 20 additions & 5 deletions pkg/agent/types/mocks/knapsack.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 25 additions & 17 deletions pkg/autoupdate/tuf/autoupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ type TufAutoupdater struct {
libraryManager librarian
osquerier querier // used to query for current running osquery version
osquerierRetryInterval time.Duration
channel string
initialDelay time.Duration
checkInterval time.Duration
knapsack types.Knapsack
store types.KVStore // stores autoupdater errors for kolide_tuf_autoupdater_errors table
interrupt chan struct{}
interrupted bool
Expand Down Expand Up @@ -93,11 +91,9 @@ func WithOsqueryRestart(restart func() error) TufAutoupdaterOption {
func NewTufAutoupdater(k types.Knapsack, metadataHttpClient *http.Client, mirrorHttpClient *http.Client,
osquerier querier, opts ...TufAutoupdaterOption) (*TufAutoupdater, error) {
ta := &TufAutoupdater{
channel: k.UpdateChannel(),
knapsack: k,
interrupt: make(chan struct{}, 1),
signalRestart: make(chan error, 1),
checkInterval: k.AutoupdateInterval(),
initialDelay: k.AutoupdateInitialDelay(),
store: k.AutoupdateErrorsStore(),
osquerier: osquerier,
osquerierRetryInterval: 30 * time.Second,
Expand Down Expand Up @@ -183,15 +179,15 @@ func (ta *TufAutoupdater) Execute() (err error) {
case <-ta.interrupt:
level.Debug(ta.logger).Log("msg", "received external interrupt during initial delay, stopping")
return nil
case <-time.After(ta.initialDelay):
case <-time.After(ta.knapsack.AutoupdateInitialDelay()):
break
}

// For now, tidy the library on startup. In the future, we will tidy the library
// earlier, after version selection.
ta.tidyLibrary()

checkTicker := time.NewTicker(ta.checkInterval)
checkTicker := time.NewTicker(ta.knapsack.AutoupdateInterval())
defer checkTicker.Stop()
cleanupTicker := time.NewTicker(12 * time.Hour)
defer cleanupTicker.Stop()
Expand Down Expand Up @@ -324,7 +320,7 @@ func (ta *TufAutoupdater) checkForUpdate() error {

// Only perform restarts if we're configured to use this new autoupdate library,
// to prevent performing unnecessary restarts.
if !ChannelUsesNewAutoupdater(ta.channel) {
if !ChannelUsesNewAutoupdater(ta.knapsack.UpdateChannel()) {
return nil
}

Expand Down Expand Up @@ -362,24 +358,36 @@ func (ta *TufAutoupdater) checkForUpdate() error {
// downloadUpdate will download a new release for the given binary, if available from TUF
// and not already downloaded.
func (ta *TufAutoupdater) downloadUpdate(binary autoupdatableBinary, targets data.TargetFiles) (string, error) {
release, releaseMetadata, err := findRelease(binary, targets, ta.channel)
release, releaseMetadata, err := findRelease(binary, targets, ta.knapsack.UpdateChannel())
if err != nil {
return "", fmt.Errorf("could not find release: %w", err)
}

if ta.libraryManager.Available(binary, release) {
return "", nil
}

// Get the current running version if available -- don't error out if we can't
// get it, since the worst case is that we download an update whose version matches
// our install version.
// Ensure we don't download duplicate versions
var currentVersion string
currentVersion, _ = ta.currentRunningVersion(binary)
if currentVersion == versionFromTarget(binary, release) {
return "", nil
}

if ta.libraryManager.Available(binary, release) {
// The release is already available in the library but we don't know if we're running it --
// err on the side of not restarting.
if currentVersion == "" {
return "", nil
}

// We're choosing to run a local build, so we don't need to restart to run a new download.
if binary == binaryLauncher && ta.knapsack.LocalDevelopmentPath() != "" {
return "", nil
}

// The release is already available in the library and it's not our current running version --
// return the version to signal for a restart.
return release, nil
}

// We haven't yet downloaded this release -- download it
if err := ta.libraryManager.AddToLibrary(binary, currentVersion, release, releaseMetadata); err != nil {
return "", fmt.Errorf("could not add release %s for binary %s to library: %w", release, binary, err)
}
Expand Down
Loading

0 comments on commit 1ac7d3e

Please sign in to comment.