From 48da76bbfc9562ef3d7a5bc7cfa0b203902dabb9 Mon Sep 17 00:00:00 2001 From: Andy Doan Date: Mon, 5 Apr 2021 13:06:49 -0500 Subject: [PATCH] Add "keys copy-targets" command This helps operators not need the super secure offline root keys for rolling out updates Signed-off-by: Andy Doan --- subcommands/keys/copy_targets.go | 68 ++++++++++++++++++++++++++++++++ subcommands/keys/rotate_root.go | 5 ++- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 subcommands/keys/copy_targets.go diff --git a/subcommands/keys/copy_targets.go b/subcommands/keys/copy_targets.go new file mode 100644 index 00000000..fd61fe51 --- /dev/null +++ b/subcommands/keys/copy_targets.go @@ -0,0 +1,68 @@ +package keys + +import ( + "encoding/json" + "errors" + "strings" + + "github.com/foundriesio/fioctl/client" + "github.com/foundriesio/fioctl/subcommands" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func init() { + copy := &cobra.Command{ + Use: "copy-targets ", + Short: "Copy the target signing credentials from the offline key archive", + Run: doCopyTargets, + Args: cobra.ExactArgs(2), + Long: `This command extracts the target signing credentials required for initializing +waves into a new tarball so that the offline key archive isn't required for +rolling out production updates. This should be run after each target key +rotation and distributed to the operator in charge of production OTAs.`, + } + subcommands.RequireFactory(copy) + cmd.AddCommand(copy) +} + +func doCopyTargets(cmd *cobra.Command, args []string) { + factory := viper.GetString("factory") + credsFile := args[0] + creds, err := GetOfflineCreds(credsFile) + subcommands.DieNotNil(err) + + root, err := api.TufRootGet(factory) + subcommands.DieNotNil(err) + + targetsCreds, err := createTargetsCreds(factory, *root, creds) + subcommands.DieNotNil(err) + saveCreds(args[1], targetsCreds) +} + +func createTargetsCreds(factory string, root client.AtsTufRoot, creds OfflineCreds) (OfflineCreds, error) { + targets := make(OfflineCreds) + onlinePub, err := api.GetFoundriesTargetsKey(factory) + subcommands.DieNotNil(err) + for _, keyid := range root.Signed.Roles["targets"].KeyIDs { + pubkey := root.Signed.Keys[keyid].KeyValue.Public + if pubkey != onlinePub.KeyValue.Public { + pubkey = strings.TrimSpace(pubkey) + for k, v := range creds { + if strings.HasSuffix(k, ".pub") { + tk := client.AtsKey{} + if err := json.Unmarshal(v, &tk); err != nil { + return nil, err + } + if strings.TrimSpace(tk.KeyValue.Public) == pubkey { + targets[k] = v + pkname := strings.Replace(k, ".pub", ".sec", 1) + targets[pkname] = creds[pkname] + return targets, nil + } + } + } + } + } + return targets, errors.New("Unable to find offline target key for factory") +} diff --git a/subcommands/keys/rotate_root.go b/subcommands/keys/rotate_root.go index c46b08c3..12d457f0 100644 --- a/subcommands/keys/rotate_root.go +++ b/subcommands/keys/rotate_root.go @@ -226,7 +226,11 @@ Please move this file somewhere safe before re-running this command.`, path, )) } + saveCreds(path, creds) + return path +} +func saveCreds(path string, creds OfflineCreds) { file, err := os.Create(path) subcommands.DieNotNil(err) defer file.Close() @@ -246,7 +250,6 @@ Please move this file somewhere safe before re-running this command.`, _, err := tarWriter.Write(val) subcommands.DieNotNil(err) } - return path } func findRoot(root client.AtsTufRoot, creds OfflineCreds) (string, *rsa.PrivateKey, error) {