Skip to content

Commit

Permalink
Use knapsack to set watchdog values; restart osquery on watchdog flag…
Browse files Browse the repository at this point in the history
… changes
  • Loading branch information
RebeccaMahany committed Dec 11, 2023
1 parent c58c937 commit 65e57cb
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 41 deletions.
1 change: 0 additions & 1 deletion cmd/launcher/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ func commonRunnerOptions(logger log.Logger, k types.Knapsack) []runtime.OsqueryI
runtime.WithAutoloadedExtensions(k.AutoloadedExtensions()...),
runtime.WithUpdateDirectory(k.UpdateDirectory()),
runtime.WithUpdateChannel(k.UpdateChannel()),
runtime.WithEnableWatchdog(k.EnableWatchdog()),
}
}

Expand Down
70 changes: 34 additions & 36 deletions pkg/osquery/runtime/osqueryinstance.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,6 @@ func WithUpdateChannel(channel string) OsqueryInstanceOption {
}
}

func WithEnableWatchdog(enableWatchdog bool) OsqueryInstanceOption {
return func(i *OsqueryInstance) {
i.opts.enableWatchdog = enableWatchdog
}
}

// WithExtensionSocketPath is a functional option which allows the user to
// define the path of the extension socket path that osqueryd will open to
// communicate with other processes.
Expand Down Expand Up @@ -324,7 +318,6 @@ type osqueryOptions struct {
distributedPluginFlag string
extensionPlugins []osquery.OsqueryPlugin
autoloadedExtensions []string
enableWatchdog bool
extensionSocketPath string
enrollSecretPath string
loggerPluginFlag string
Expand Down Expand Up @@ -465,61 +458,66 @@ func calculateOsqueryPaths(opts osqueryOptions) (*osqueryFilePaths, error) {

// createOsquerydCommand uses osqueryOptions to return an *exec.Cmd
// which will launch a properly configured osqueryd process.
func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths *osqueryFilePaths) (*exec.Cmd, error) {
func (o *OsqueryInstance) createOsquerydCommand(osquerydBinary string, paths *osqueryFilePaths) (*exec.Cmd, error) {
// Create the reference instance for the running osquery instance
args := []string{
fmt.Sprintf("--logger_plugin=%s", opts.loggerPluginFlag),
fmt.Sprintf("--distributed_plugin=%s", opts.distributedPluginFlag),
fmt.Sprintf("--logger_plugin=%s", o.opts.loggerPluginFlag),
fmt.Sprintf("--distributed_plugin=%s", o.opts.distributedPluginFlag),
"--disable_distributed=false",
"--distributed_interval=5",
"--pack_delimiter=:",
"--host_identifier=uuid",
"--force=true",
"--utc",
}
if !opts.enableWatchdog {

if o.knapsack != nil && o.knapsack.EnableWatchdog() {
args = append(args, fmt.Sprintf("--watchdog_memory_limit=%d", o.knapsack.WatchdogMemoryLimitMB()))
args = append(args, fmt.Sprintf("--watchdog_utilization_limit=%d", o.knapsack.WatchdogUtilizationLimitPercent()))
args = append(args, fmt.Sprintf("--watchdog_delay=%d", o.knapsack.WatchdogDelaySec()))
} else {
args = append(args, "--disable_watchdog")
}

cmd := exec.Command( //nolint:forbidigo // We trust the autoupdate library to find the correct path
osquerydBinary,
args...,
)

if opts.verbose {
if o.opts.verbose {
cmd.Args = append(cmd.Args, "--verbose")
}

if opts.tlsHostname != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--tls_hostname=%s", opts.tlsHostname))
if o.opts.tlsHostname != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--tls_hostname=%s", o.opts.tlsHostname))
}

if opts.tlsConfigEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--config_tls_endpoint=%s", opts.tlsConfigEndpoint))

if o.opts.tlsConfigEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--config_tls_endpoint=%s", o.opts.tlsConfigEndpoint))
}

if opts.tlsEnrollEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--enroll_tls_endpoint=%s", opts.tlsEnrollEndpoint))
if o.opts.tlsEnrollEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--enroll_tls_endpoint=%s", o.opts.tlsEnrollEndpoint))
}

if opts.tlsLoggerEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--logger_tls_endpoint=%s", opts.tlsLoggerEndpoint))
if o.opts.tlsLoggerEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--logger_tls_endpoint=%s", o.opts.tlsLoggerEndpoint))
}

if opts.tlsDistReadEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--distributed_tls_read_endpoint=%s", opts.tlsDistReadEndpoint))
if o.opts.tlsDistReadEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--distributed_tls_read_endpoint=%s", o.opts.tlsDistReadEndpoint))
}

if opts.tlsDistWriteEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--distributed_tls_write_endpoint=%s", opts.tlsDistWriteEndpoint))
if o.opts.tlsDistWriteEndpoint != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--distributed_tls_write_endpoint=%s", o.opts.tlsDistWriteEndpoint))
}

if opts.tlsServerCerts != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--tls_server_certs=%s", opts.tlsServerCerts))
if o.opts.tlsServerCerts != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--tls_server_certs=%s", o.opts.tlsServerCerts))
}

if opts.enrollSecretPath != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--enroll_secret_path=%s", opts.enrollSecretPath))
if o.opts.enrollSecretPath != "" {
cmd.Args = append(cmd.Args, fmt.Sprintf("--enroll_secret_path=%s", o.opts.enrollSecretPath))
}

// Configs aren't expected to change often, so refresh configs
Expand All @@ -536,16 +534,16 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths *
}

cmd.Args = append(cmd.Args, platformArgs()...)
if opts.stdout != nil {
cmd.Stdout = opts.stdout
if o.opts.stdout != nil {
cmd.Stdout = o.opts.stdout
}
if opts.stderr != nil {
cmd.Stderr = opts.stderr
if o.opts.stderr != nil {
cmd.Stderr = o.opts.stderr
}

// Apply user-provided flags last so that they can override other flags set
// by Launcher (besides the flags below)
for _, flag := range opts.osqueryFlags {
for _, flag := range o.opts.osqueryFlags {
cmd.Args = append(cmd.Args, "--"+flag)
}

Expand All @@ -559,8 +557,8 @@ func (opts *osqueryOptions) createOsquerydCommand(osquerydBinary string, paths *
fmt.Sprintf("--extensions_autoload=%s", paths.extensionAutoloadPath),
"--disable_extensions=false",
"--extensions_timeout=20",
fmt.Sprintf("--config_plugin=%s", opts.configPluginFlag),
fmt.Sprintf("--extensions_require=%s", strings.Join(opts.requiredExtensions(), ",")),
fmt.Sprintf("--config_plugin=%s", o.opts.configPluginFlag),
fmt.Sprintf("--extensions_require=%s", strings.Join(o.opts.requiredExtensions(), ",")),
)

// On darwin, run osquery using a magic macOS variable to ensure we
Expand Down
18 changes: 17 additions & 1 deletion pkg/osquery/runtime/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/go-kit/kit/log/level"
"github.com/kolide/launcher/ee/agent/flags/keys"
"github.com/kolide/launcher/ee/tuf"
"github.com/kolide/launcher/pkg/autoupdate"
"github.com/kolide/launcher/pkg/backoff"
Expand Down Expand Up @@ -83,6 +84,10 @@ func (r *Runner) Start(cancel context.CancelFunc) error {
if err := r.launchOsqueryInstance(); err != nil {
return fmt.Errorf("starting instance: %w", err)
}
r.instance.knapsack.RegisterChangeObserver(r,
keys.EnableWatchdog, keys.WatchdogMemoryLimitMB, keys.WatchdogUtilizationLimitPercent, keys.WatchdogDelaySec,
)

go func() {
// This loop waits for the completion of the async routines,
// and either restarts the instance (if Shutdown was not
Expand Down Expand Up @@ -170,6 +175,17 @@ func (r *Runner) Shutdown() error {
return nil
}

// FlagsChanged satisfies the types.FlagsChangeObserver interface -- handles updates to flags
// that we care about, which are enable_watchdog, watchdog_delay_sec, watchdog_memory_limit_mb,
// and watchdog_utilization_limit_percent.
func (r *Runner) FlagsChanged(flagKeys ...keys.FlagKey) {
level.Debug(r.instance.logger).Log("msg", "control server flags changed, restarting instance to apply", "flags", fmt.Sprintf("%+v", flagKeys))

if err := r.Restart(); err != nil {
level.Error(r.instance.logger).Log("msg", "could not restart osquery instance after flag change")
}
}

// Restart allows you to cleanly shutdown the current instance and launch a new
// instance with the same configurations.
func (r *Runner) Restart() error {
Expand Down Expand Up @@ -327,7 +343,7 @@ func (r *Runner) launchOsqueryInstance() error {
// Now that we have accepted options from the caller and/or determined what
// they should be due to them not being set, we are ready to create and start
// the *exec.Cmd instance that will run osqueryd.
o.cmd, err = o.opts.createOsquerydCommand(currentOsquerydBinaryPath, paths)
o.cmd, err = o.createOsquerydCommand(currentOsquerydBinaryPath, paths)
if err != nil {
traces.SetError(span, fmt.Errorf("couldn't create osqueryd command: %w", err))
return fmt.Errorf("couldn't create osqueryd command: %w", err)
Expand Down
Loading

0 comments on commit 65e57cb

Please sign in to comment.