Allow disabling auto updates in fleetctl package and orbit (#4296)

* Add disable-updates flag to fleetctl and orbit

* Fix ruleguard execution error on make lint-go

* Introduce dev-mode for ease of development of orbit

* Add changes file
This commit is contained in:
Lucas Manuel Rodriguez 2022-02-18 15:42:39 -03:00 committed by GitHub
parent 8e68ec3b96
commit c641e39ef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 120 additions and 46 deletions

View File

@ -0,0 +1 @@
* Add flag to `fleetctl package` and `orbit` to disable auto updates.

View File

@ -4,7 +4,7 @@ import (
"context"
"database/sql"
"encoding/json"
"fmt"
"errors"
"io/ioutil"
"os"
"testing"
@ -286,7 +286,7 @@ func TestApplyPolicies(t *testing.T) {
if name == "Team1" {
return &fleet.Team{ID: 123}, nil
}
return nil, fmt.Errorf("unexpected team name!")
return nil, errors.New("unexpected team name!")
}
ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activityType string, details *map[string]interface{}) error {
return nil

View File

@ -88,6 +88,11 @@ func packageCommand() *cli.Command {
Value: "stable",
Destination: &opt.OrbitChannel,
},
&cli.BoolFlag{
Name: "disable-updates",
Usage: "Disable auto updates on the generated package",
Destination: &opt.DisableUpdates,
},
&cli.StringFlag{
Name: "update-url",
Usage: "URL for update server",

1
go.mod
View File

@ -70,6 +70,7 @@ require (
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.17 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/rotisserie/eris v0.5.1
github.com/rs/zerolog v1.20.0

2
go.sum
View File

@ -986,6 +986,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quasilyte/go-ruleguard/dsl v0.3.17 h1:L5xf3nifnRIdYe9vyMuY2sDnZHIgQol/fDq74FQz7ZY=
github.com/quasilyte/go-ruleguard/dsl v0.3.17/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=

View File

@ -183,9 +183,26 @@ Press Enter to continue, or Control-c to exit.
If you want to run orbit from source directly, you can do the following:
```sh
go run github.com/fleetdm/fleet/v4/orbit/cmd/orbit --root-dir /tmp/orbit -- --flagfile=flagfile.txt --verbose
go run github.com/fleetdm/fleet/v4/orbit/cmd/orbit \
--dev-mode \
--disable-updates \
--root-dir /tmp/orbit \
--fleet-url https://localhost:8080 \
--insecure \
--enroll-secret Pz3zC0NMDdZfb3FtqiLgwoexItojrYh/ \
-- --verbose
```
Or, using a `flagfile.txt` for osqueryd:
```sh
go run github.com/fleetdm/fleet/v4/orbit/cmd/orbit \
--dev-mode \
--disable-updates \
--root-dir /tmp/orbit \
-- --flagfile=flagfile.txt --verbose
```
### Troubleshooting
#### Logs

View File

@ -96,6 +96,16 @@ func main() {
Value: "stable",
EnvVars: []string{"ORBIT_ORBIT_CHANNEL"},
},
&cli.BoolFlag{
Name: "disable-updates",
Usage: "Disables auto updates",
EnvVars: []string{"ORBIT_DISABLE_UPDATES"},
},
&cli.BoolFlag{
Name: "dev-mode",
Usage: "Runs in development mode",
EnvVars: []string{"ORBIT_DEV_MODE"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug logging",
@ -177,22 +187,35 @@ func main() {
log.Fatal().Err(err).Msg("failed to create local metadata store")
}
// Initialize updater and get expected version
// Get the default osqueryd path from the installation/configuration.
osquerydPath := update.LocalPath(c.String("root-dir"), "osqueryd", c.String("osqueryd-channel"), constant.PlatformName)
if c.Bool("disable-updates") {
log.Info().Msg("running with auto updates disabled")
}
var updater *update.Updater
if !c.Bool("disable-updates") ||
// When running in dev-mode, even if `disable-updates` is set, fetch osqueryd once as part
// of initialization.
c.Bool("dev-mode") {
// Initialize updater and get expected version of osqueryd.
opt := update.DefaultOptions
opt.RootDirectory = c.String("root-dir")
opt.ServerURL = c.String("update-url")
opt.LocalStore = localStore
opt.InsecureTransport = c.Bool("insecure")
updater, err := update.New(opt)
updater, err = update.New(opt)
if err != nil {
return err
return fmt.Errorf("failed to create updater: %w", err)
}
if err := updater.UpdateMetadata(); err != nil {
log.Info().Err(err).Msg("failed to update metadata. using saved metadata.")
}
osquerydPath, err := updater.Get("osqueryd", c.String("osqueryd-channel"))
osquerydPath, err = updater.Get("osqueryd", c.String("osqueryd-channel"))
if err != nil {
return err
return fmt.Errorf("failed to get osqueryd target: %w", err)
}
}
// Clear leftover files from updates
@ -215,6 +238,7 @@ func main() {
var g run.Group
if !c.Bool("disable-updates") {
updateRunner, err := update.NewRunner(updater, update.RunnerOptions{
CheckInterval: 10 * time.Second,
Targets: map[string]string{
@ -226,8 +250,9 @@ func main() {
return err
}
g.Add(updateRunner.Execute, updateRunner.Interrupt)
}
var options []func(*osquery.Runner) error
var options []osquery.Option
options = append(options, osquery.WithDataPath(c.String("root-dir")))
options = append(options, osquery.WithLogPath(path.Join(c.String("root-dir"), "osquery_log")))
@ -328,7 +353,7 @@ func main() {
osquery.WithFlags([]string{"--tls_server_certs", certPath}),
)
} else {
certPath := filepath.Join(opt.RootDirectory, "certs.pem")
certPath := filepath.Join(c.String("root-dir"), "certs.pem")
if exists, err := file.Exists(certPath); err == nil && exists {
_, err = certificate.LoadPEM(certPath)
if err != nil {
@ -364,8 +389,11 @@ func main() {
// override all other flags and flagfile entries.
options = append(options, osquery.WithFlags(c.Args().Slice()))
// Create an osquery runner with the provided options
r, _ := osquery.NewRunner(osquerydPath, options...)
// Create an osquery runner with the provided options.
r, err := osquery.NewRunner(osquerydPath, options...)
if err != nil {
return fmt.Errorf("failed to create osquery runner: %w", err)
}
g.Add(r.Execute, r.Interrupt)
if runtime.GOOS != "windows" {

View File

@ -3,6 +3,7 @@ package osquery
import (
"context"
"errors"
"fmt"
"io"
"os"
@ -31,8 +32,19 @@ type Runner struct {
cancel func()
}
type Option func(*Runner) error
// NewRunner creates a new osquery runner given the provided functional options.
func NewRunner(path string, options ...func(*Runner) error) (*Runner, error) {
func NewRunner(path string, options ...Option) (*Runner, error) {
switch _, err := os.Stat(path); {
case err == nil:
// OK
case errors.Is(err, os.ErrNotExist):
return nil, fmt.Errorf("osqueryd doesn't exist at path %q", path)
default:
return nil, fmt.Errorf("failed to check for osqueryd file: %w", err)
}
r := &Runner{}
cmd := exec.Command(path)
@ -53,7 +65,7 @@ func NewRunner(path string, options ...func(*Runner) error) (*Runner, error) {
}
// WithFlags adds additional flags to the osqueryd invocation.
func WithFlags(flags []string) func(*Runner) error {
func WithFlags(flags []string) Option {
return func(r *Runner) error {
r.cmd.Args = append(r.cmd.Args, flags...)
return nil
@ -62,7 +74,7 @@ func WithFlags(flags []string) func(*Runner) error {
// WithEnv adds additional environment variables to the osqueryd invocation.
// Inputs should be in the form "KEY=VAL".
func WithEnv(env []string) func(*Runner) error {
func WithEnv(env []string) Option {
return func(r *Runner) error {
r.cmd.Env = append(r.cmd.Env, env...)
return nil
@ -78,7 +90,7 @@ func WithShell() func(*Runner) error {
}
}
func WithDataPath(path string) func(*Runner) error {
func WithDataPath(path string) Option {
return func(r *Runner) error {
r.dataPath = path
@ -96,14 +108,14 @@ func WithDataPath(path string) func(*Runner) error {
}
// WithStderr sets the runner's cmd's stderr to the given writer.
func WithStderr(w io.Writer) func(*Runner) error {
func WithStderr(w io.Writer) Option {
return func(r *Runner) error {
r.cmd.Stderr = w
return nil
}
}
func WithLogPath(path string) func(*Runner) error {
func WithLogPath(path string) Option {
return func(r *Runner) error {
if err := secure.MkdirAll(path, constant.DefaultDirMode); err != nil {
return fmt.Errorf("initialize osquery log path: %w", err)

View File

@ -196,6 +196,7 @@ ORBIT_UPDATE_URL={{ .UpdateURL }}
ORBIT_ORBIT_CHANNEL={{ .OrbitChannel }}
ORBIT_OSQUERYD_CHANNEL={{ .OsquerydChannel }}
{{ if .Insecure }}ORBIT_INSECURE=true{{ end }}
{{ if .DisableUpdates }}ORBIT_DISABLE_UPDATES=true{{ end }}
{{ if .FleetURL }}ORBIT_FLEET_URL={{.FleetURL}}{{ end }}
{{ if .FleetCertificate }}ORBIT_FLEET_CERTIFICATE=/var/lib/orbit/fleet.pem{{ end }}
{{ if .EnrollSecret }}ORBIT_ENROLL_SECRET={{.EnrollSecret}}{{ end }}

View File

@ -84,6 +84,10 @@ var macosLaunchdTemplate = template.Must(template.New("").Option("missingkey=err
<key>ORBIT_FLEET_URL</key>
<string>{{ .FleetURL }}</string>
{{- end }}
{{- if .DisableUpdates }}
<key>ORBIT_DISABLE_UPDATES</key>
<string>true</string>
{{- end }}
<key>ORBIT_ORBIT_CHANNEL</key>
<string>{{ .OrbitChannel }}</string>
<key>ORBIT_OSQUERYD_CHANNEL</key>

View File

@ -39,6 +39,8 @@ type Options struct {
Notarize bool
// FleetCertificate is a path to a server certificate to include in the package.
FleetCertificate string
// DisableUpdates disables auto updates on the generated package.
DisableUpdates bool
// OrbitChannel is the update channel to use for Orbit.
OrbitChannel string
// OsquerydChannel is the update channel to use for Osquery (osqueryd).

View File

@ -53,7 +53,7 @@ var windowsWixTemplate = template.Must(template.New("").Option("missingkey=error
ErrorControl="ignore"
Start="auto"
Type="ownProcess"
Arguments='--root-dir "[ORBITROOT]." --log-file "[System64Folder]config\systemprofile\AppData\Local\FleetDM\Orbit\Logs\orbit-osquery.log" {{ if .FleetURL }}--fleet-url "{{ .FleetURL }}"{{ end }} {{ if .FleetCertificate }}--fleet-certificate "[ORBITROOT]fleet.pem"{{ end }} {{ if .EnrollSecret }}--enroll-secret-path "[ORBITROOT]secret.txt"{{ end }} {{if .Insecure }}--insecure{{ end }} {{ if .Debug }}--debug{{ end }} {{ if .UpdateURL }}--update-url "{{ .UpdateURL }}" {{ end }} --orbit-channel "{{ .OrbitChannel }}" --osqueryd-channel "{{ .OsquerydChannel }}"'
Arguments='--root-dir "[ORBITROOT]." --log-file "[System64Folder]config\systemprofile\AppData\Local\FleetDM\Orbit\Logs\orbit-osquery.log"{{ if .FleetURL }} --fleet-url "{{ .FleetURL }}"{{ end }}{{ if .FleetCertificate }} --fleet-certificate "[ORBITROOT]fleet.pem"{{ end }}{{ if .EnrollSecret }} --enroll-secret-path "[ORBITROOT]secret.txt"{{ end }}{{if .Insecure }} --insecure{{ end }}{{ if .Debug }} --debug{{ end }}{{ if .UpdateURL }} --update-url "{{ .UpdateURL }}"{{ end }}{{ if .DisableUpdates }} --disable-updates{{ end }} --orbit-channel "{{ .OrbitChannel }}" --osqueryd-channel "{{ .OsquerydChannel }}"'
>
<util:ServiceConfig
FirstFailureActionType="restart"

View File

@ -125,8 +125,13 @@ func (u *Updater) RepoPath(target, channel string) string {
return path.Join(target, u.opt.Platform, channel, target+constant.ExecutableExtension(u.opt.Platform))
}
// LocalPath defines the local file path of a target.
func LocalPath(rootDir, target, channel, platform string) string {
return filepath.Join(rootDir, binDir, target, platform, channel, target+constant.ExecutableExtension(platform))
}
func (u *Updater) LocalPath(target, channel string) string {
return u.pathFromRoot(filepath.Join(binDir, target, u.opt.Platform, channel, target+constant.ExecutableExtension(u.opt.Platform)))
return LocalPath(u.opt.RootDirectory, target, channel, u.opt.Platform)
}
// Lookup looks up the provided target in the local target metadata. This should
@ -300,13 +305,9 @@ func (u *Updater) Download(repoPath, localPath string) error {
return nil
}
func (u *Updater) pathFromRoot(parts ...string) string {
return filepath.Join(append([]string{u.opt.RootDirectory}, parts...)...)
}
func (u *Updater) initializeDirectories() error {
for _, dir := range []string{
u.pathFromRoot(binDir),
filepath.Join(u.opt.RootDirectory, binDir),
} {
err := secure.MkdirAll(dir, constant.DefaultDirMode)
if err != nil {