From a8b25e33a0df06998cfffd5707bc727f662fdd8d Mon Sep 17 00:00:00 2001 From: Din Music Date: Thu, 5 Sep 2024 12:13:35 +0000 Subject: [PATCH] lxd-migrate: Add cert-path/key-path flags In non-interactive mode, the --cert-path and --key-path must point to an already trusted certificate. Signed-off-by: Din Music --- lxd-migrate/main_migrate.go | 24 ++++++++++++++++++++++-- lxd-migrate/utils.go | 17 +++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lxd-migrate/main_migrate.go b/lxd-migrate/main_migrate.go index 81257e544e1e..aa8fb7d40257 100644 --- a/lxd-migrate/main_migrate.go +++ b/lxd-migrate/main_migrate.go @@ -48,8 +48,10 @@ type cmdMigrate struct { flagSource string // Target server. - flagServer string - flagToken string + flagServer string + flagToken string + flagCertPath string + flagKeyPath string // Other. flagRsyncArgs string @@ -89,6 +91,8 @@ func (c *cmdMigrate) command() *cobra.Command { // Target server. cmd.Flags().StringVar(&c.flagServer, "server", "", "Unix or HTTPS URL of the target server"+"``") cmd.Flags().StringVar(&c.flagToken, "token", "", "Authentication token for HTTPS remote"+"``") + cmd.Flags().StringVar(&c.flagCertPath, "cert-path", "", "Trusted certificate path"+"``") + cmd.Flags().StringVar(&c.flagKeyPath, "key-path", "", "Trusted certificate key path"+"``") // Other flags. cmd.Flags().StringVar(&c.flagRsyncArgs, "rsync-args", "", "Extra arguments to pass to rsync"+"``") @@ -157,6 +161,11 @@ func (c *cmdMigrate) askServer() (lxd.InstanceServer, string, error) { var serverURL string var err error + // Ensure trust token is not used along trust certificate and/or its corresponding key. + if c.flagToken != "" && (c.flagCertPath != "" || c.flagKeyPath != "") { + return nil, "", fmt.Errorf("Authentication token is mutually exclusive with certificate path and key") + } + if c.flagNonInteractive || c.flagServer != "" { // Try to connect to unix socket if server URL is empty or has a "unix:" prefix. if c.flagServer == "" || strings.HasPrefix(c.flagServer, "unix:") { @@ -262,6 +271,17 @@ func (c *cmdMigrate) askServer() (lxd.InstanceServer, string, error) { if err != nil { return nil, "", fmt.Errorf("Failed to decode certificate token: %w", err) } + } else if c.flagKeyPath != "" || c.flagCertPath != "" { + if c.flagKeyPath == "" { + return nil, "", errors.New("Certificate path is required when certificate key is set") + } + + if c.flagCertPath == "" { + return nil, "", errors.New("Certificate key path is required when certificate path is set") + } + + certPath = c.flagCertPath + keyPath = c.flagKeyPath } else { if c.flagNonInteractive { return nil, "", errors.New("Authentication token is required for HTTPS remote in non-interactive mode") diff --git a/lxd-migrate/utils.go b/lxd-migrate/utils.go index 15ecc4f2b596..f1106cdfb5db 100644 --- a/lxd-migrate/utils.go +++ b/lxd-migrate/utils.go @@ -250,6 +250,23 @@ func (c *cmdMigrate) connectTarget(url string, certPath string, keyPath string, if err != nil { return nil, "", fmt.Errorf("Failed to create certificate: %w", err) } + } else if c.flagNonInteractive { + // In non-interactive mode stop at this point, as we know that the server + // does not trust us, but we should not make any further interaction with the caller. + if certPath != "" || keyPath != "" { + return nil, "", fmt.Errorf("Provided certificate is not trusted by the server") + } + + return nil, "", errors.New("Failed to authenticate with the server: Please, either provide a trust token or an already trusted certificate") + } else if instanceServer.HasExtension("explicit_trust_token") { + fmt.Println("A temporary client certificate was generated, use `lxc config trust add` on the target server.") + fmt.Println("") + + fmt.Print("Press ENTER after the certificate was added to the remote server: ") + _, err = bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + return nil, "", err + } } else { fmt.Println("It is recommended to have this certificate be manually added to LXD through `lxc config trust add` on the target server.\nAlternatively you could use a pre-defined trust password to add it remotely (use of a trust password can be a security issue).")