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)).
This commit is contained in:
Lucas Manuel Rodriguez
2025-01-10 14:27:30 -03:00
committed by GitHub
parent 5873cb9ef7
commit 009f54bdda
23 changed files with 1150 additions and 107 deletions
+4 -2
View File
@@ -51,7 +51,8 @@ jobs:
make generate-doc
if [[ $(git diff) ]]; then
echo "❌ fail: uncommited changes"
echo "please run `make generate-doc` and commit the changes"
echo "please run 'make generate-doc' and commit the changes"
git --no-pager diff
exit 1
fi
@@ -62,6 +63,7 @@ jobs:
./node_modules/sails/bin/sails.js run generate-merged-schema
if [[ $(git diff) ]]; then
echo "❌ fail: uncommited changes"
echo "please run `cd website && npm install && ./node_modules/sails/bin/sails.js run generate-merged-schema` and commit the changes"
echo "please run 'cd website && npm install && ./node_modules/sails/bin/sails.js run generate-merged-schema' and commit the changes"
git --no-pager diff
exit 1
fi
+2 -1
View File
@@ -13,6 +13,7 @@ import (
eefleetctl "github.com/fleetdm/fleet/v4/ee/fleetctl"
"github.com/fleetdm/fleet/v4/orbit/pkg/packaging"
"github.com/fleetdm/fleet/v4/orbit/pkg/update"
"github.com/fleetdm/fleet/v4/pkg/filepath_windows"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/rs/zerolog"
@@ -127,7 +128,7 @@ func packageCommand() *cli.Command {
&cli.StringFlag{
Name: "update-url",
Usage: "URL for update server",
Value: "https://tuf.fleetctl.com",
Value: update.DefaultURL,
Destination: &opt.UpdateURL,
},
&cli.StringFlag{
+1 -1
View File
@@ -762,7 +762,7 @@ func previewResetCommand() *cli.Command {
return fmt.Errorf("Failed to stop orbit: %w", err)
}
if err := os.RemoveAll(filepath.Join(orbitDir, "tuf-metadata.json")); err != nil {
if err := os.RemoveAll(filepath.Join(orbitDir, update.MetadataFileName)); err != nil {
return fmt.Errorf("failed to remove preview update metadata file: %w", err)
}
if err := os.RemoveAll(filepath.Join(orbitDir, "bin")); err != nil {
+1
View File
@@ -0,0 +1 @@
* Added changes to migrate to new TUF repository from https://tuf.fleetctl.com to https://updates.fleetdm.com.
+57 -8
View File
@@ -471,7 +471,26 @@ func main() {
}
}
localStore, err := filestore.New(filepath.Join(c.String("root-dir"), "tuf-metadata.json"))
if updateURL := c.String("update-url"); updateURL != update.OldFleetTUFURL && updateURL != update.DefaultURL {
// Migrate agents running with a custom TUF to use the new metadata file.
// We'll keep the old metadata file to support downgrades.
newMetadataFilePath := filepath.Join(c.String("root-dir"), update.MetadataFileName)
ok, err := file.Exists(newMetadataFilePath)
if err != nil {
// If we cannot stat this file then we cannot do other operations on it thus we fail with fatal error.
log.Fatal().Err(err).Msg("failed to check for new metadata file path")
}
if !ok {
oldMetadataFilePath := filepath.Join(c.String("root-dir"), update.OldMetadataFileName)
err := file.Copy(oldMetadataFilePath, newMetadataFilePath, constant.DefaultFileMode)
if err != nil {
// If we cannot write to this file then we cannot do other operations on it thus we fail with fatal error.
log.Fatal().Err(err).Msg("failed to copy new metadata file path")
}
}
}
localStore, err := filestore.New(filepath.Join(c.String("root-dir"), update.MetadataFileName))
if err != nil {
log.Fatal().Err(err).Msg("create local metadata store")
}
@@ -503,6 +522,29 @@ func main() {
opt.RootDirectory = c.String("root-dir")
opt.ServerURL = c.String("update-url")
checkAccessToNewTUF := false
if opt.ServerURL == update.OldFleetTUFURL {
//
// This only gets executed on orbit 1.38.0+
// when it is configured to connect to the old TUF server
// (fleetd instances packaged before the migration,
// built by fleetctl previous to v4.63.0).
//
if ok := update.HasAccessToNewTUFServer(opt); ok {
// orbit 1.38.0+ will use the new TUF server if it has access to the new TUF repository.
opt.ServerURL = update.DefaultURL
} else {
// orbit 1.38.0+ will use the old TUF server and old metadata path if it does not have access
// to the new TUF repository. During its execution (update.Runner) it will exit once it finds
// out it can access the new TUF server.
localStore, err = filestore.New(filepath.Join(c.String("root-dir"), update.OldMetadataFileName))
if err != nil {
log.Fatal().Err(err).Msg("create local old metadata store")
}
checkAccessToNewTUF = true
}
}
opt.LocalStore = localStore
opt.InsecureTransport = c.Bool("insecure")
opt.ServerCertificatePath = c.String("update-tls-certificate")
@@ -545,13 +587,12 @@ func main() {
var updater *update.Updater
var updateRunner *update.Runner
if !c.Bool("disable-updates") || c.Bool("dev-mode") {
updater, err = update.NewUpdater(opt)
updater, err := update.NewUpdater(opt)
if err != nil {
return fmt.Errorf("create updater: %w", err)
}
if err := updater.UpdateMetadata(); err != nil {
log.Info().Err(err).Msg("update metadata, using saved metadata")
log.Info().Err(err).Msg("update metadata")
}
signaturesExpiredAtStartup := updater.SignaturesExpired()
@@ -571,6 +612,7 @@ func main() {
CheckInterval: c.Duration("update-interval"),
Targets: targets,
SignaturesExpiredAtStartup: signaturesExpiredAtStartup,
CheckAccessToNewTUF: checkAccessToNewTUF,
})
if err != nil {
return err
@@ -1394,10 +1436,17 @@ func getFleetdComponentPaths(
log.Error().Err(err).Msg("update metadata before getting components")
}
// "root", "targets", or "snapshot" signatures have expired, thus
// we attempt to get local paths for the targets (updater.Get will fail
// because of the expired signatures).
if updater.SignaturesExpired() {
//
// updater.SignaturesExpired():
// "root", "targets", or "snapshot" signatures have expired, thus
// we attempt to get local paths for the targets (updater.Get will fail
// because of the expired signatures).
//
// updater.LookupsFail():
// Any of the targets fails to load thus we resort to the local executables we have.
// This could happen if the new TUF server is down during the first run of the TUF migration.
//
if updater.SignaturesExpired() || updater.LookupsFail() {
log.Error().Err(err).Msg("expired metadata, using local targets")
// Attempt to get local path of osqueryd.
+1 -1
View File
@@ -47,7 +47,7 @@ var shellCommand = &cli.Command{
return fmt.Errorf("initialize root dir: %w", err)
}
localStore, err := filestore.New(filepath.Join(c.String("root-dir"), "tuf-metadata.json"))
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")
}
+12 -1
View File
@@ -172,7 +172,7 @@ func (u UpdatesData) String() string {
}
func InitializeUpdates(updateOpt update.Options) (*UpdatesData, error) {
localStore, err := filestore.New(filepath.Join(updateOpt.RootDirectory, "tuf-metadata.json"))
localStore, err := filestore.New(filepath.Join(updateOpt.RootDirectory, update.MetadataFileName))
if err != nil {
return nil, fmt.Errorf("failed to create local metadata store: %w", err)
}
@@ -236,6 +236,17 @@ func InitializeUpdates(updateOpt update.Options) (*UpdatesData, error) {
}
}
// Copy the new metadata file to the old location (pre-migration) to
// support orbit downgrades to 1.37.0 or lower.
//
// Once https://tuf.fleetctl.com is brought down (which means downgrades to 1.37.0 or
// lower won't be possible), we can remove this copy.
oldMetadataPath := filepath.Join(updateOpt.RootDirectory, update.OldMetadataFileName)
newMetadataPath := filepath.Join(updateOpt.RootDirectory, update.MetadataFileName)
if err := file.Copy(newMetadataPath, oldMetadataPath, constant.DefaultFileMode); err != nil {
return nil, fmt.Errorf("failed to create %s copy: %w", oldMetadataPath, err)
}
return &UpdatesData{
OrbitPath: orbitPath,
OrbitVersion: orbitCustom.Version,
+2 -2
View File
@@ -6,8 +6,8 @@ import (
var defaultOptions = Options{
RootDirectory: "/opt/orbit",
ServerURL: defaultURL,
RootKeys: defaultRootKeys,
ServerURL: DefaultURL,
RootKeys: defaultRootMetadata,
LocalStore: client.MemoryLocalStore(),
InsecureTransport: false,
Targets: DarwinTargets,
+2 -2
View File
@@ -6,8 +6,8 @@ import (
var defaultOptions = Options{
RootDirectory: "/opt/orbit",
ServerURL: defaultURL,
RootKeys: defaultRootKeys,
ServerURL: DefaultURL,
RootKeys: defaultRootMetadata,
LocalStore: client.MemoryLocalStore(),
InsecureTransport: false,
Targets: LinuxTargets,
+2 -2
View File
@@ -6,8 +6,8 @@ import (
var defaultOptions = Options{
RootDirectory: "/opt/orbit",
ServerURL: defaultURL,
RootKeys: defaultRootKeys,
ServerURL: DefaultURL,
RootKeys: defaultRootMetadata,
LocalStore: client.MemoryLocalStore(),
InsecureTransport: false,
Targets: LinuxArm64Targets,
+2 -2
View File
@@ -9,8 +9,8 @@ import (
var defaultOptions = Options{
RootDirectory: `C:\Program Files\Orbit`,
ServerURL: defaultURL,
RootKeys: defaultRootKeys,
ServerURL: DefaultURL,
RootKeys: defaultRootMetadata,
LocalStore: client.MemoryLocalStore(),
InsecureTransport: false,
Targets: WindowsTargets,
+20
View File
@@ -39,6 +39,11 @@ type RunnerOptions struct {
// An expired signature for the "timestamp" role does not cause issues
// at start up (the go-tuf libary allows loading the targets).
SignaturesExpiredAtStartup bool
// CheckAccessToNewTUF, if set to true, will perform a check of access to the new Fleet TUF
// server on every update interval (once the access is confirmed it will store the confirmation
// of access to disk and will exit to restart).
CheckAccessToNewTUF bool
}
// Runner is a specialized runner for an Updater. It is designed with Execute and
@@ -121,6 +126,14 @@ func NewRunner(updater *Updater, opt RunnerOptions) (*Runner, error) {
return runner, nil
}
if _, err := updater.Lookup(constant.OrbitTUFTargetName); errors.Is(err, client.ErrNoLocalSnapshot) {
// Return early and skip optimization, this will cause an unnecessary auto-update of orbit
// but allows orbit to start up if there's no local metadata AND if the TUF server is down
// (which may be the case during the migration from https://tuf.fleetctl.com to
// https://updates.fleetdm.com).
return runner, nil
}
// Initialize the hashes of the local files for all tracked targets.
//
// This is an optimization to not compute the hash of the local files every opt.CheckInterval
@@ -204,6 +217,13 @@ func (r *Runner) Execute() error {
case <-ticker.C:
ticker.Reset(r.opt.CheckInterval)
if r.opt.CheckAccessToNewTUF {
if HasAccessToNewTUFServer(r.updater.opt) {
log.Info().Msg("detected access to new TUF repository, exiting")
return nil
}
}
if r.opt.SignaturesExpiredAtStartup {
if r.updater.SignaturesExpired() {
log.Debug().Msg("signatures still expired")
File diff suppressed because one or more lines are too long
+9 -11
View File
@@ -69,18 +69,16 @@ AWS_PROFILE=tuf aws sso login
> You can skip this step if you already have authorized keys to sign and publish updates.
To release updates to our TUF repository you need the `root` role (ask in Slack who has such `root` role) to sign your signing keys.
First, run the following script
```sh
AWS_PROFILE=tuf \
ACTION=generate-signing-keys \
TUF_DIRECTORY=/Users/foobar/tuf3.fleetctl.com \
TARGETS_PASSPHRASE_1PASSWORD_PATH="Private/TUF TARGETS/password" \
SNAPSHOT_PASSPHRASE_1PASSWORD_PATH="Private/TUF SNAPSHOT/password" \
TIMESTAMP_PASSPHRASE_1PASSWORD_PATH="Private/TUF TIMESTAMP/password" \
./tools/tuf/releaser.sh
```
The human with the `root` role will run the following commands to sign the provided `staged/root.json`:
1. First, run the following script
```sh
tuf gen-key targets && echo
tuf gen-key snapshot && echo
tuf gen-key timestamp && echo
```
2. Store the '$TUF_DIRECTORY/keys' folder (that contains the encrypted keys) on a USB flash drive that you will ONLY use for releasing fleetd updates.
3. Share '$TUF_DIRECTORY/staged/root.json' with Fleet member with the 'root' role, who will sign with its root key and push it to the remote repository.
4. The human with the `root` role will run the following commands to sign the provided `staged/root.json`:
```sh
tuf sign
tuf snapshot
+22
View File
@@ -0,0 +1,22 @@
# migrate
This tool will be used to migrate all current targets (except unused ones) from https://tuf.fleetctl.com to https://updates.fleetdm.com.
Usage:
```sh
# The tool requires the 'targets', 'snapshot' and 'timestamp' roles of the new repository.
export FLEET_TARGETS_PASSPHRASE=p4ssphr4s3
export FLEET_SNAPSHOT_PASSPHRASE=p4ssphr4s3
export FLEET_TIMESTAMP_PASSPHRASE=p4ssphr4s3
#
# It assumes the following:
# - https://tuf.fleetctl.com was fully fetched into -source-repository-directory.
# - https://updates.fleetdm.com was fully fetched into -dest-repository-directory.
#
# Migration may take several minutes due to sha512 verification after targets are
# added to the new repository.
go run ./tools/tuf/migrate/migrate.go \
-source-repository-directory ./source-tuf-directory \
-dest-repository-directory ./dest-tuf-directory
```
+207
View File
@@ -0,0 +1,207 @@
// Package main contains an executable that migrates all targets from one source TUF repository
// to a destination TUF repository. It migrates all targets except a few known unused targets.
package main
import (
"crypto/sha512"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)
func main() {
if runtime.GOOS == "windows" {
log.Fatalf("%s is not supported on windows", os.Args[0])
}
sourceRepositoryDirectory := flag.String("source-repository-directory", "", "Absolute path directory for the source TUF")
destRepositoryDirectory := flag.String("dest-repository-directory", "", "Absolute path directory for the destination TUF")
flag.Parse()
if *sourceRepositoryDirectory == "" {
log.Fatal("missing --source-repository-directory")
}
if *destRepositoryDirectory == "" {
log.Fatal("missing --dest-repository-directory")
}
type targetEntry struct {
sha512 string
length int
}
// Perform addition of targets by iterating source repository.
sourceEntries := make(map[string]targetEntry)
iterateRepository(*sourceRepositoryDirectory, func(target, targetPath, platform, targetName, version, channel, hashSHA512 string, length int) error {
cmd := exec.Command("fleetctl", "updates", "add", //nolint:gosec
"--path", *destRepositoryDirectory,
"--target", targetPath,
"--platform", platform,
"--name", targetName,
"--version", version,
"-t", channel,
)
log.Print(cmd.String())
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
log.Fatalf("target: %q: failed to add target: %s", target, err)
}
sourceEntries[target] = targetEntry{
sha512: hashSHA512,
length: length,
}
return nil
})
// Perform validation of destination repository.
iterateRepository(*destRepositoryDirectory, func(target, targetPath, platform, targetName, version, channel, hashSHA512 string, length int) error {
sourceEntry, ok := sourceEntries[target]
if !ok {
return errors.New("entry not found in source directory")
}
// It seems this very old version has invalid length and sha256.
// Validation fails with:
// 2025/01/07 18:11:40 target: "desktop/macos/1.11.0/desktop.app.tar.gz": failed to process target: mismatch length: 10518528 vs 30373384
if target == "desktop/macos/1.11.0/desktop.app.tar.gz" {
log.Printf("Skipping %s (old version) due to invalid length and sha256", target)
return nil
}
if sourceEntry.length != length {
return fmt.Errorf("mismatch length: %d vs %d", length, sourceEntry.length)
}
if sourceEntry.sha512 != hashSHA512 {
return fmt.Errorf("mismatch sha512: %s vs %s", hashSHA512, sourceEntry.sha512)
}
targetBytes, err := os.ReadFile(targetPath)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
h := sha512.New()
if _, err := h.Write(targetBytes); err != nil {
return fmt.Errorf("failed to hash file: %w", err)
}
fileHash := hex.EncodeToString(h.Sum(nil))
if fileHash != sourceEntry.sha512 {
return fmt.Errorf("mismatch sha512 and file contents: %s vs %s", fileHash, sourceEntry.sha512)
}
return nil
})
}
func iterateRepository(repositoryDirectory string, fn func(target, targetPath, platform, targetName, version, channel, sha512 string, length int) error) {
repositoryPath := filepath.Join(repositoryDirectory, "repository")
targetsFile := filepath.Join(repositoryPath, "targets.json")
targetsBytes, err := os.ReadFile(targetsFile)
if err != nil {
log.Fatal("failed to read the source targets.json file")
}
var targetsJSON map[string]interface{}
if err := json.Unmarshal(targetsBytes, &targetsJSON); err != nil {
log.Fatal("failed to parse the source targets.json file")
}
signed_ := targetsJSON["signed"]
if signed_ == nil {
log.Fatal("missing signed key in targets.json file")
}
signed, ok := signed_.(map[string]interface{})
if !ok {
log.Fatalf("invalid signed key in targets.json file: %T, expected map", signed_)
}
targets_ := signed["targets"]
if targets_ == nil {
log.Fatal("missing signed.targets key in targets.json file")
}
targets, ok := targets_.(map[string]interface{})
if !ok {
log.Fatalf("invalid signed.targets key in targets.json file: %T, expected map", targets_)
}
for target, metadata_ := range targets {
targetPath := filepath.Join(repositoryPath, "targets", target)
parts := strings.Split(target, "/")
if len(parts) != 4 {
log.Fatalf("target %q: invalid number of parts, expected 4", target)
}
targetName := parts[0]
platform := parts[1]
channel := parts[2]
executable := parts[3]
// Unused targets (probably accidentally pushed).
if targetName == "desktop.tar.gz" || // correct target name is just "desktop".
(targetName == "desktop" && executable == "desktop") { // correct executable for Linux is "desktop.tar.gz".
continue
}
metadata, ok := metadata_.(map[string]interface{})
if !ok {
log.Fatalf("target: %q: invalid metadata field: %T, expected map", target, metadata_)
}
custom_ := metadata["custom"]
if custom_ == nil {
log.Fatalf("target: %q: missing custom field", target)
}
custom, ok := custom_.(map[string]interface{})
if !ok {
log.Fatalf("target: %q: invalid custom field: %T, expected map", target, custom_)
}
version_ := custom["version"]
if version_ == nil {
log.Fatalf("target: %q: missing custom.version field", target)
}
version, ok := version_.(string)
if !ok {
log.Fatalf("target: %q: invalid custom.version field: %T", target, version_)
}
length_ := metadata["length"]
if length_ == nil {
log.Fatalf("target: %q: missing length field", target)
}
lengthf, ok := length_.(float64)
if !ok {
log.Fatalf("target: %q: invalid length field: %T", target, length_)
}
length := int(lengthf)
hashes_ := metadata["hashes"]
if hashes_ == nil {
log.Fatalf("target: %q: missing hashes field", target)
}
hashes, ok := hashes_.(map[string]interface{})
if !ok {
log.Fatalf("target: %q: invalid hashes field: %T", target, hashes_)
}
sha512_ := hashes["sha512"]
if sha512_ == nil {
log.Fatalf("target: %q: missing hashes.sha512 field", target)
}
hashSHA512, ok := sha512_.(string)
if !ok {
log.Fatalf("target: %q: invalid hashes.sha512 field: %T", target, sha512_)
}
if err := fn(target, targetPath, platform, targetName, version, channel, hashSHA512, length); err != nil {
log.Fatalf("target: %q: failed to process target: %s", target, err)
}
}
}
+7 -35
View File
@@ -277,41 +277,6 @@ prompt () {
done
}
setup_to_become_publisher () {
echo "Running setup to become publisher..."
REPOSITORY_DIRECTORY=$TUF_DIRECTORY/repository
STAGED_DIRECTORY=$TUF_DIRECTORY/staged
KEYS_DIRECTORY=$TUF_DIRECTORY/keys
mkdir -p "$REPOSITORY_DIRECTORY"
mkdir -p "$STAGED_DIRECTORY"
mkdir -p "$KEYS_DIRECTORY"
if ! aws sts get-caller-identity &> /dev/null; then
aws sso login
prompt "AWS SSO login was successful."
fi
# These need to be exported for use by `tuf` commands.
FLEET_TARGETS_PASSPHRASE=$(op read "op://$TARGETS_PASSPHRASE_1PASSWORD_PATH")
export TUF_TARGETS_PASSPHRASE=$FLEET_TARGETS_PASSPHRASE
FLEET_SNAPSHOT_PASSPHRASE=$(op read "op://$SNAPSHOT_PASSPHRASE_1PASSWORD_PATH")
export TUF_SNAPSHOT_PASSPHRASE=$FLEET_SNAPSHOT_PASSPHRASE
FLEET_TIMESTAMP_PASSPHRASE=$(op read "op://$TIMESTAMP_PASSPHRASE_1PASSWORD_PATH")
export TUF_TIMESTAMP_PASSPHRASE=$FLEET_TIMESTAMP_PASSPHRASE
}
if [[ $ACTION == "generate-signing-keys" ]]; then
setup_to_become_publisher
pull_from_remote
cd "$TUF_DIRECTORY"
tuf gen-key targets && echo
tuf gen-key snapshot && echo
tuf gen-key timestamp && echo
echo "Keys have been generated, now do the following actions:"
echo "- Share '$TUF_DIRECTORY/staged/root.json' with Fleet member with the 'root' role, who will sign with its root key and push it to the remote repository."
echo "- Store the '$TUF_DIRECTORY/keys' folder (that contains the encrypted keys) on a USB flash drive that you will ONLY use for releasing fleetd updates."
exit 0
fi
print_reminder () {
if [[ $ACTION == "release-to-edge" ]]; then
if [[ $COMPONENT == "fleetd" ]]; then
@@ -333,8 +298,15 @@ print_reminder () {
fi
}
fleetctl_version_check () {
which fleetctl
fleetctl --version
prompt "Make sure the fleetctl executable and version are correct."
}
trap clean_up EXIT
print_reminder
fleetctl_version_check
setup
pull_from_remote
+2 -1
View File
@@ -61,7 +61,8 @@ LINUX_TEST_EXTENSIONS="./tools/test_extensions/hello_world/linux/hello_world_lin
To build for a specific architecture, you can pass the `GOARCH` environment variable:
``` shell
[...]
GOARCH=arm64 # defaults to amd64
# defaults to amd64
GOARCH=arm64 \
[...]
./tools/tuf/test/main.sh
```
+13 -3
View File
@@ -6,10 +6,19 @@ export FLEET_ROOT_PASSPHRASE=p4ssphr4s3
export FLEET_TARGETS_PASSPHRASE=p4ssphr4s3
export FLEET_SNAPSHOT_PASSPHRASE=p4ssphr4s3
export FLEET_TIMESTAMP_PASSPHRASE=p4ssphr4s3
export TUF_PATH=test_tuf
export NUDGE=1
if ( [ -n "$GENERATE_PKG" ] || [ -n "$GENERATE_DEB" ] || [ -n "$GENERATE_RPM" ] || [ -n "$GENERATE_MSI" ] ) && [ -z "$ENROLL_SECRET" ]; then
if [ -z "$TUF_PATH" ]; then
TUF_PATH=test_tuf
fi
export TUF_PATH
if [ -z "$TUF_PORT" ]; then
TUF_PORT=8081
fi
export TUF_PORT
if { [ -n "$GENERATE_PKG" ] || [ -n "$GENERATE_DEB" ] || [ -n "$GENERATE_RPM" ] || [ -n "$GENERATE_MSI" ] ; } && [ -z "$ENROLL_SECRET" ]; then
echo "Error: To generate packages you must set ENROLL_SECRET variable."
exit 1
fi
@@ -30,7 +39,8 @@ fi
make fleetctl
./tools/tuf/test/create_repository.sh
export ROOT_KEYS=$(./build/fleetctl updates roots --path $TUF_PATH)
ROOT_KEYS=$(./build/fleetctl updates roots --path "$TUF_PATH")
export ROOT_KEYS
echo "#########"
echo "To generate packages set the following options in 'fleetctl package':"
+21
View File
@@ -0,0 +1,21 @@
# `migration_test.sh`
This script is used to test the migration from one local TUF repository to a new local TUF repository (with new roots).
> Currently supports running on macOS only.
The script is interactive and assumes the user will use a Windows and Ubuntu VM to install fleetd and test the changes on those platforms too.
Usage:
```sh
FLEET_URL=https://host.docker.internal:8080 \
NO_TEAM_ENROLL_SECRET=... \
WINDOWS_HOST_HOSTNAME=DESKTOP-USFLJ3H \
LINUX_HOST_HOSTNAME=foobar-ubuntu \
./tools/tuf/test/migration/migration_test.sh
```
To simulate an outage of the TUF during the migration run the above with:
```sh
SIMULATE_NEW_TUF_OUTAGE=1 \
```
+597
View File
@@ -0,0 +1,597 @@
#!/bin/bash
# Script used to test the migration from a TUF repository to a new one.
# It assumes the following:
# - User runs the script on macOS
# - User has a Ubuntu 22.04 and a Windows 10/11 VM (running on the same macOS host script runs on).
# - Fleet is running on the macOS host.
# - `fleetctl login` was ran on the localhost Fleet instance (to be able to run `fleectl query` commands).
# - host.docker.internal points to localhost on the macOS host.
# - host.docker.internal points to the macOS host on the two VMs (/etc/hosts on Ubuntu and C:\Windows\System32\Drivers\etc\hosts on Windows).
# - 1.37.0 is the last version of orbit that uses the old TUF repository
# - 1.38.0 is the new version of orbit that will use the new TUF repository.
# - Old TUF repository directory is ./test_tuf_old and server listens on 8081 (runs on the macOS host).
# - New TUF repository directory is ./test_tuf_new and server listens on 8082 (runs on the macOS host).
set -e
if [ -z "$FLEET_URL" ]; then
echo "Missing FLEET_URL"
exit 1
fi
if [ -z "$NO_TEAM_ENROLL_SECRET" ]; then
echo "Missing NO_TEAM_ENROLL_SECRET"
exit 1
fi
if [ -z "$WINDOWS_HOST_HOSTNAME" ]; then
echo "Missing WINDOWS_HOST_HOSTNAME"
exit 1
fi
if [ -z "$LINUX_HOST_HOSTNAME" ]; then
echo "Missing LINUX_HOST_HOSTNAME"
exit 1
fi
prompt () {
printf "%s\n" "$1"
printf "Type 'yes' to continue... "
while read -r word;
do
if [[ "$word" == "yes" ]]; then
printf "\n"
return
fi
done
}
echo "Uinstalling fleetd from macOS..."
sudo orbit/tools/cleanup/cleanup_macos.sh
prompt "Please manually uninstall fleetd from $WINDOWS_HOST_HOSTNAME and $LINUX_HOST_HOSTNAME."
OLD_TUF_PORT=8081
OLD_TUF_URL=http://host.docker.internal:$OLD_TUF_PORT
OLD_TUF_PATH=test_tuf_old
OLD_FULL_VERSION=1.37.0
OLD_MINOR_VERSION=1.37
NEW_TUF_PORT=8082
NEW_TUF_URL=http://host.docker.internal:$NEW_TUF_PORT
NEW_TUF_PATH=test_tuf_new
NEW_FULL_VERSION=1.38.0
NEW_MINOR_VERSION=1.38
NEW_PATCH_VERSION=1.38.1
echo "Cleaning up existing directories and file servers..."
rm -rf "$OLD_TUF_PATH"
rm -rf "$NEW_TUF_PATH"
pkill file-server || true
echo "Restoring update_channels for \"No team\" to 'stable' defaults..."
cat << EOF > upgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: stable
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f upgrade.yml
echo "Generating a TUF repository on $OLD_TUF_PATH (aka \"old\")..."
SYSTEMS="macos linux windows" \
TUF_PATH=$OLD_TUF_PATH \
TUF_PORT=$OLD_TUF_PORT \
FLEET_DESKTOP=1 \
./tools/tuf/test/main.sh
export FLEET_ROOT_PASSPHRASE=p4ssphr4s3
export FLEET_TARGETS_PASSPHRASE=p4ssphr4s3
export FLEET_SNAPSHOT_PASSPHRASE=p4ssphr4s3
export FLEET_TIMESTAMP_PASSPHRASE=p4ssphr4s3
echo "Downloading and pushing latest released orbit from https://tuf.fleetctl.com to the old repository..."
curl https://tuf.fleetctl.com/targets/orbit/macos/$OLD_FULL_VERSION/orbit --output orbit-darwin
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $OLD_FULL_VERSION -t $OLD_MINOR_VERSION -t 1 -t stable
curl https://tuf.fleetctl.com/targets/orbit/linux/$OLD_FULL_VERSION/orbit --output orbit-linux
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $OLD_FULL_VERSION -t $OLD_MINOR_VERSION -t 1 -t stable
curl https://tuf.fleetctl.com/targets/orbit/windows/$OLD_FULL_VERSION/orbit.exe --output orbit.exe
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $OLD_FULL_VERSION -t $OLD_MINOR_VERSION -t 1 -t stable
echo "Building fleetd packages using old repository and old fleetctl version..."
curl -L https://github.com/fleetdm/fleet/releases/download/fleet-v4.60.0/fleetctl_v4.60.0_macos.tar.gz --output ./build/fleetctl_v4.60.0_macos.tar.gz
cd ./build
tar zxf fleetctl_v4.60.0_macos.tar.gz
cp fleetctl_v4.60.0_macos/fleetctl fleetctl-v4.60.0
cd ..
chmod +x ./build/fleetctl-v4.60.0
ROOT_KEYS1=$(./build/fleetctl-v4.60.0 updates roots --path $OLD_TUF_PATH)
declare -a pkgTypes=("pkg" "deb" "msi")
for pkgType in "${pkgTypes[@]}"; do
./build/fleetctl-v4.60.0 package --type="$pkgType" \
--enable-scripts \
--fleet-desktop \
--fleet-url="$FLEET_URL" \
--enroll-secret="$NO_TEAM_ENROLL_SECRET" \
--fleet-certificate=./tools/osquery/fleet.crt \
--debug \
--update-roots="$ROOT_KEYS1" \
--update-url=$OLD_TUF_URL \
--disable-open-folder \
--disable-keystore \
--update-interval=30s
done
# Install fleetd generated with old fleetctl and using old TUF on devices.
echo "Installing fleetd package on macOS..."
sudo installer -pkg fleet-osquery.pkg -verbose -target /
CURRENT_DIR=$(pwd)
prompt "Please install $CURRENT_DIR/fleet-osquery.msi and $CURRENT_DIR/fleet-osquery_${OLD_FULL_VERSION}_amd64.deb."
echo "Generating a new TUF repository from scratch on $NEW_TUF_PATH..."
./build/fleetctl updates init --path $NEW_TUF_PATH
echo "Migrating all targets from old to new repository..."
go run ./tools/tuf/migrate/migrate.go \
-source-repository-directory "$OLD_TUF_PATH" \
-dest-repository-directory "$NEW_TUF_PATH"
echo "Serving new TUF repository..."
TUF_PORT=$NEW_TUF_PORT TUF_PATH=$NEW_TUF_PATH ./tools/tuf/test/run_server.sh
echo "Building the new orbit that will perform the migration..."
ROOT_KEYS2=$(./build/fleetctl updates roots --path $NEW_TUF_PATH)
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \
-o orbit-darwin \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_FULL_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-o orbit-linux \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_FULL_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
-o orbit.exe \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_FULL_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
echo "Pushing new orbit to new repository on stable channel..."
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
if [ "$SIMULATE_NEW_TUF_OUTAGE" = "1" ]; then
echo "Simulating outage of the new TUF repository by killing the new TUF server..."
# We kill the two servers and bring back the old one.
pkill file-server || true
TUF_PORT=$OLD_TUF_PORT TUF_PATH=$OLD_TUF_PATH ./tools/tuf/test/run_server.sh
fi
echo "Pushing new orbit to old repository!..."
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $NEW_FULL_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
if [ "$SIMULATE_NEW_TUF_OUTAGE" = "1" ]; then
echo "Checking version of updated orbit (to check device is responding even if TUF server is down)..."
THIS_HOSTNAME=$(hostname)
declare -a hostnames=("$THIS_HOSTNAME" "$WINDOWS_HOST_HOSTNAME" "$LINUX_HOST_HOSTNAME")
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
prompt "Please check for errors in orbit logs that new TUF server is unavailable (network errors). Errors should be shown every 10s."
echo "Bring new TUF server back but still unavailable (404s errors)."
mkdir -p $NEW_TUF_PATH/tmp
mv $NEW_TUF_PATH/repository/targets/* $NEW_TUF_PATH/tmp/
TUF_PORT=$NEW_TUF_PORT TUF_PATH=$NEW_TUF_PATH ./tools/tuf/test/run_server.sh
prompt "Please check for errors in orbit logs that new TUF server is still unavailable (404s errors). Errors should be shown every 10s."
echo "Checking version of orbit (to check device is responding even if TUF server is down)..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
# We kill the two servers and bring back the old one.
pkill file-server || true
TUF_PORT=$OLD_TUF_PORT TUF_PATH=$OLD_TUF_PATH ./tools/tuf/test/run_server.sh
# Restore files on the new repository.
mv $NEW_TUF_PATH/tmp/* $NEW_TUF_PATH/repository/targets/
if [ "$ORBIT_PATCH_IN_OLD_TUF" = "1" ]; then
echo "Build and push a new update to orbit to old and new repository (to test patching an invalid 1.38.0 would work for customers without access to new TUF)"
ROOT_KEYS2=$(./build/fleetctl updates roots --path $NEW_TUF_PATH)
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \
-o orbit-darwin \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-o orbit-linux \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
-o orbit.exe \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $OLD_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
echo "Checking orbit has auto-updated to $NEW_PATCH_VERSION using old TUF..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
# Now the next patch version will be 1.38.2.
NEW_FULL_VERSION=1.38.1
NEW_PATCH_VERSION=1.38.2
fi
echo "Restoring new TUF repository..."
TUF_PORT=$NEW_TUF_PORT TUF_PATH=$NEW_TUF_PATH ./tools/tuf/test/run_server.sh
prompt "Please check that devices have restarted and started communicating with the new TUF (now that it's available)"
fi
echo "Checking version of updated orbit..."
THIS_HOSTNAME=$(hostname)
declare -a hostnames=("$THIS_HOSTNAME" "$WINDOWS_HOST_HOSTNAME" "$LINUX_HOST_HOSTNAME")
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Restarting fleetd on the macOS host..."
sudo launchctl unload /Library/LaunchDaemons/com.fleetdm.orbit.plist && sudo launchctl load /Library/LaunchDaemons/com.fleetdm.orbit.plist
prompt "Please restart fleetd on the Linux and Windows host."
echo "Checking version of updated orbit..."
THIS_HOSTNAME=$(hostname)
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Building and pushing a new update to orbit on the new repository (to test upgrades are working)..."
ROOT_KEYS2=$(./build/fleetctl updates roots --path $NEW_TUF_PATH)
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \
-o orbit-darwin \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-o orbit-linux \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
-o orbit.exe \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/build.Version=$NEW_PATCH_VERSION \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.OldFleetTUFURL=$OLD_TUF_URL" \
./orbit/cmd/orbit
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-darwin --platform macos --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit-linux --platform linux --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
./build/fleetctl updates add --path $NEW_TUF_PATH --target ./orbit.exe --platform windows --name orbit --version $NEW_PATCH_VERSION -t $NEW_MINOR_VERSION -t 1 -t stable
echo "Waiting until update happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Downgrading to $OLD_FULL_VERSION..."
cat << EOF > downgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: '$OLD_FULL_VERSION'
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f downgrade.yml
echo "Waiting until downgrade happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$OLD_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Restoring to latest orbit version..."
cat << EOF > upgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: stable
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f upgrade.yml
echo "Waiting until upgrade happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Building fleetd packages using old repository and old fleetctl version that should auto-update to new orbit that talks to new repository..."
for pkgType in "${pkgTypes[@]}"; do
./build/fleetctl-v4.60.0 package --type="$pkgType" \
--enable-scripts \
--fleet-desktop \
--fleet-url="$FLEET_URL" \
--enroll-secret="$NO_TEAM_ENROLL_SECRET" \
--fleet-certificate=./tools/osquery/fleet.crt \
--debug \
--update-roots="$ROOT_KEYS1" \
--update-url=$OLD_TUF_URL \
--disable-open-folder \
--disable-keystore \
--update-interval=30s
done
echo "Installing fleetd package on macOS..."
sudo installer -pkg fleet-osquery.pkg -verbose -target /
CURRENT_DIR=$(pwd)
prompt "Please install $CURRENT_DIR/fleet-osquery.msi and $CURRENT_DIR/fleet-osquery_${NEW_FULL_VERSION}_amd64.deb."
echo "Waiting until installation and auto-update to new repository happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Downgrading to $OLD_FULL_VERSION..."
cat << EOF > downgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: '$OLD_FULL_VERSION'
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f downgrade.yml
echo "Waiting until downgrade happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$OLD_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Restoring to latest orbit version..."
cat << EOF > upgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: stable
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f upgrade.yml
echo "Waiting until upgrade happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Building fleetd packages using new repository and new fleetctl version..."
CGO_ENABLED=0 go build \
-o ./build/fleetctl \
-ldflags="-X github.com/fleetdm/fleet/v4/orbit/pkg/update.defaultRootMetadata=$ROOT_KEYS2 \
-X github.com/fleetdm/fleet/v4/orbit/pkg/update.DefaultURL=$NEW_TUF_URL" \
./cmd/fleetctl
for pkgType in "${pkgTypes[@]}"; do
./build/fleetctl package --type="$pkgType" \
--enable-scripts \
--fleet-desktop \
--fleet-url="$FLEET_URL" \
--enroll-secret="$NO_TEAM_ENROLL_SECRET" \
--fleet-certificate=./tools/osquery/fleet.crt \
--debug \
--disable-open-folder \
--disable-keystore \
--update-interval=30s
done
echo "Installing fleetd package on macOS..."
sudo installer -pkg fleet-osquery.pkg -verbose -target /
CURRENT_DIR=$(pwd)
prompt "Please install $CURRENT_DIR/fleet-osquery.msi and $CURRENT_DIR/fleet-osquery_${NEW_PATCH_VERSION}_amd64.deb."
echo "Waiting until installation and auto-update to new repository happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$NEW_PATCH_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
cat << EOF > downgrade.yml
---
apiVersion: v1
kind: config
spec:
agent_options:
config:
options:
pack_delimiter: /
distributed_plugin: tls
disable_distributed: false
logger_tls_endpoint: /api/v1/osquery/log
distributed_interval: 10
distributed_tls_max_attempts: 3
distributed_denylist_duration: 10
decorators:
load:
- SELECT uuid AS host_uuid FROM system_info;
- SELECT hostname AS hostname FROM system_info;
update_channels:
orbit: '$OLD_FULL_VERSION'
desktop: stable
osqueryd: stable
EOF
fleetctl apply -f downgrade.yml
echo "Waiting until downgrade happens..."
for host_hostname in "${hostnames[@]}"; do
ORBIT_VERSION=""
until [ "$ORBIT_VERSION" = "\"$OLD_FULL_VERSION\"" ]; do
sleep 1
ORBIT_VERSION=$(fleetctl query --hosts "$host_hostname" --exit --query 'SELECT * FROM orbit_info;' 2>/dev/null | jq '.rows[0].version')
done
done
echo "Migration testing completed."
+5 -1
View File
@@ -4,7 +4,11 @@ system=$1
target_name=$2
target_path=$3
major_version=$4
TUF_PATH=test_tuf
if [ -z "$TUF_PATH" ]; then
TUF_PATH=test_tuf
fi
export TUF_PATH
export FLEET_ROOT_PASSPHRASE=p4ssphr4s3
export FLEET_TARGETS_PASSPHRASE=p4ssphr4s3
+8 -4
View File
@@ -2,10 +2,14 @@
set -e
pkill file-server || true
echo "Running TUF server"
go run ./tools/file-server 8081 "${TUF_PATH}/repository" &
until curl --silent -o /dev/null http://localhost:8081/root.json; do
if curl --silent -o /dev/null "http://localhost:$TUF_PORT/root.json" ; then
echo "TUF server already running"
exit 0
fi
echo "Start TUF server"
go run ./tools/file-server "$TUF_PORT" "${TUF_PATH}/repository" &
until curl --silent -o /dev/null "http://localhost:$TUF_PORT/root.json"; do
sleep 1
done
echo "TUF server started"