fleet/orbit/cmd/orbit/shell.go
Lucas Manuel Rodriguez 009f54bdda
Changes to migrate to new TUF repository (#23588)
# Changes

- orbit >= 1.38.0, when configured to connect to
https://tuf.fleetctl.com (existing fleetd deployments) will now connect
to https://updates.fleetdm.com and start using the metadata in path
`/opt/orbit/updates-metadata.json`.
- orbit >= 1.38.0, when configured to connect to some custom TUF (not
Fleet's TUFs) will copy `/opt/orbit/tuf-metadata.json` to
`/opt/orbit/updates-metadata.json` (if it doesn't exist) and start using
the latter.
- fleetctl `4.63.0` will now generate artifacts using
https://updates.fleetdm.com by default (or a custom TUF if
`--update-url` is set) and generate two (same file) metadata files
`/opt/orbit/updates-metadata.json` and the legacy one to support
downgrades `/opt/orbit/tuf-metadata.json`.
- fleetctl `4.62.0` when configured to use custom TUF (not Fleet's TUF)
will generate just the legacy metadata file
`/opt/orbit/tuf-metadata.json`.

## User stories

See "User stories" in
https://github.com/fleetdm/confidential/issues/8488.

- [x] Update `update.defaultRootMetadata` and `update.DefaultURL` when
the new repository is ready.
- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
- For Orbit and Fleet Desktop changes:
- [X] Orbit runs on macOS, Linux and Windows. Check if the orbit
feature/bugfix should only apply to one platform (`runtime.GOOS`).
- [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)).
2025-01-10 14:27:30 -03:00

142 lines
4.2 KiB
Go

package main
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/fleetdm/fleet/v4/orbit/pkg/constant"
"github.com/fleetdm/fleet/v4/orbit/pkg/osquery"
"github.com/fleetdm/fleet/v4/orbit/pkg/update"
"github.com/fleetdm/fleet/v4/orbit/pkg/update/filestore"
"github.com/fleetdm/fleet/v4/pkg/secure"
"github.com/google/uuid"
"github.com/oklog/run"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
)
var shellCommand = &cli.Command{
Name: "shell",
Aliases: []string{"osqueryi"},
Usage: "Run the osqueryi shell",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "osqueryd-channel",
Usage: "Channel of osqueryd version to use",
Value: "stable",
EnvVars: []string{"ORBIT_OSQUERYD_CHANNEL"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug logging",
EnvVars: []string{"ORBIT_DEBUG"},
},
},
Action: func(c *cli.Context) error {
zerolog.SetGlobalLevel(zerolog.InfoLevel)
if c.Bool("debug") {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
if err := secure.MkdirAll(c.String("root-dir"), constant.DefaultDirMode); err != nil {
return fmt.Errorf("initialize root dir: %w", err)
}
localStore, err := filestore.New(filepath.Join(c.String("root-dir"), update.MetadataFileName))
if err != nil {
log.Fatal().Err(err).Msg("failed to create local metadata store")
}
// Initialize updater and get expected version
opt := update.DefaultOptions
// Override default channel with the provided value.
opt.Targets.SetTargetChannel(constant.OsqueryTUFTargetName, c.String("osqueryd-channel"))
opt.RootDirectory = c.String("root-dir")
opt.ServerURL = c.String("update-url")
opt.LocalStore = localStore
opt.InsecureTransport = c.Bool("insecure")
updater, err := update.NewUpdater(opt)
if err != nil {
return err
}
if err := updater.UpdateMetadata(); err != nil {
log.Info().Err(err).Msg("failed to update metadata. using saved metadata.")
}
osquerydLocalTarget, err := updater.Get(constant.OsqueryTUFTargetName)
if err != nil {
return err
}
osquerydPath := osquerydLocalTarget.ExecPath
var g run.Group
// We use a suffix on the extension path on Windows
// because there was an issue when the osqueryd instance ran through
// `orbit shell` attempted to register the same named pipe name used by
// the osqueryd instance launched by orbit service.
extensionPathPostfix := ""
if runtime.GOOS == "windows" {
extensionPathPostfix = "-" + uuid.New().String()
}
// We use a different path from the orbit daemon
// to avoid issues with concurrent accesses to files/databases
// (RocksDB lock and/or Windows file locking).
dataPath := filepath.Join(c.String("root-dir"), "shell")
osqueryDB := filepath.Join(dataPath, "osquery.db")
opts := []osquery.Option{
osquery.WithShell(),
osquery.WithDataPath(dataPath, extensionPathPostfix),
osquery.WithFlags([]string{"--database_path", osqueryDB}),
}
// Detect if the additional arguments have a positional argument.
//
// osqueryi/osqueryd has the following usage:
// Usage: osqueryi [OPTION]... [SQL STATEMENT]
additionalArgs := c.Args().Slice()
singleQueryArg := false
if len(additionalArgs) > 0 {
if !strings.HasPrefix(additionalArgs[len(additionalArgs)-1], "--") {
singleQueryArg = true
opts = append(opts, osquery.SingleQuery())
}
}
// Handle additional args after --
opts = append(opts, osquery.WithFlags(additionalArgs))
r, err := osquery.NewRunner(osquerydPath, opts...)
if err != nil {
return fmt.Errorf("create osquery runner: %w", err)
}
g.Add(r.Execute, r.Interrupt)
if !singleQueryArg {
// We currently start the extension runner when !singleQueryArg
// because otherwise osquery exits and leaves too quickly,
// leaving the extension runner waiting for the socket.
// NOTE(lucas): `--extensions_require` doesn't seem to work with
// thrift extensions?
registerExtensionRunner(&g, r.ExtensionSocketPath()+extensionPathPostfix)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g.Add(run.SignalHandler(ctx, os.Interrupt, os.Kill))
if err := g.Run(); err != nil {
log.Error().Err(err).Msg("unexpected exit")
}
return nil
},
}