open-vault/command/operator_unseal.go

166 lines
4.1 KiB
Go
Raw Permalink Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-03-04 07:57:23 +00:00
package command
import (
2015-03-04 08:35:02 +00:00
"fmt"
2017-09-05 04:05:27 +00:00
"io"
"os"
2015-03-04 07:57:23 +00:00
"strings"
"github.com/hashicorp/go-secure-stdlib/password"
2018-10-23 06:34:02 +00:00
"github.com/hashicorp/vault/api"
2017-09-05 04:05:27 +00:00
"github.com/mitchellh/cli"
"github.com/posener/complete"
2015-03-04 07:57:23 +00:00
)
var (
_ cli.Command = (*OperatorUnsealCommand)(nil)
_ cli.CommandAutocomplete = (*OperatorUnsealCommand)(nil)
)
2017-09-05 04:05:27 +00:00
2017-09-08 02:03:12 +00:00
type OperatorUnsealCommand struct {
2017-09-05 04:05:27 +00:00
*BaseCommand
2018-10-23 06:34:02 +00:00
flagReset bool
flagMigrate bool
2017-09-05 04:05:27 +00:00
testOutput io.Writer // for tests
}
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) Synopsis() string {
2017-09-05 04:05:27 +00:00
return "Unseals the Vault server"
}
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) Help() string {
2017-09-05 04:05:27 +00:00
helpText := `
2017-09-08 02:03:12 +00:00
Usage: vault operator unseal [options] [KEY]
2017-09-05 04:05:27 +00:00
Provide a portion of the root key to unseal a Vault server. Vault starts
2017-09-05 04:05:27 +00:00
in a sealed state. It cannot perform operations until it is unsealed. This
command accepts a portion of the root key (an "unseal key").
2017-09-05 04:05:27 +00:00
The unseal key can be supplied as an argument to the command, but this is
not recommended as the unseal key will be available in your history:
2017-09-08 02:03:12 +00:00
$ vault operator unseal IXyR0OJnSFobekZMMCKCoVEpT7wI6l+USMzE3IcyDyo=
2017-09-05 04:05:27 +00:00
Instead, run the command with no arguments and it will prompt for the key:
2017-09-08 02:03:12 +00:00
$ vault operator unseal
2017-09-05 04:05:27 +00:00
Key (will be hidden): IXyR0OJnSFobekZMMCKCoVEpT7wI6l+USMzE3IcyDyo=
` + c.Flags().Help()
return strings.TrimSpace(helpText)
}
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) Flags() *FlagSets {
CLI Enhancements (#3897) * Use Colored UI if stdout is a tty * Add format options to operator unseal * Add format test on operator unseal * Add -no-color output flag, and use BasicUi if no-color flag is provided * Move seal status formatting logic to OutputSealStatus * Apply no-color to warnings from DeprecatedCommands as well * Add OutputWithFormat to support arbitrary data, add format option to auth list * Add ability to output arbitrary list data on TableFormatter * Clear up switch logic on format * Add format option for list-related commands * Add format option to rest of commands that returns a client API response * Remove initOutputYAML and initOutputJSON, and use OutputWithFormat instead * Remove outputAsYAML and outputAsJSON, and use OutputWithFormat instead * Remove -no-color flag, use env var exclusively to toggle colored output * Fix compile * Remove -no-color flag in main.go * Add missing FlagSetOutputFormat * Fix generate-root/decode test * Migrate init functions to main.go * Add no-color flag back as hidden * Handle non-supported data types for TableFormatter.OutputList * Pull formatting much further up to remove the need to use c.flagFormat (#3950) * Pull formatting much further up to remove the need to use c.flagFormat Also remove OutputWithFormat as the logic can cause issues. * Use const for env var * Minor updates * Remove unnecessary check * Fix SSH output and some tests * Fix tests * Make race detector not run on generate root since it kills Travis these days * Update docs * Update docs * Address review feedback * Handle --format as well as -format
2018-02-12 23:12:16 +00:00
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
2017-09-05 04:05:27 +00:00
f := set.NewFlagSet("Command Options")
f.BoolVar(&BoolVar{
Name: "reset",
Aliases: []string{},
Target: &c.flagReset,
Default: false,
EnvVar: "",
Completion: complete.PredictNothing,
Usage: "Discard any previously entered keys to the unseal process.",
})
2018-10-23 06:34:02 +00:00
f.BoolVar(&BoolVar{
Name: "migrate",
Aliases: []string{},
Target: &c.flagMigrate,
Default: false,
EnvVar: "",
Completion: complete.PredictNothing,
Usage: "Indicate that this share is provided with the intent that it is part of a seal migration process.",
})
2017-09-05 04:05:27 +00:00
return set
}
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) AutocompleteArgs() complete.Predictor {
2017-09-21 17:38:39 +00:00
return complete.PredictAnything
2017-09-05 04:05:27 +00:00
}
2015-03-14 03:17:55 +00:00
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) AutocompleteFlags() complete.Flags {
2017-09-05 04:05:27 +00:00
return c.Flags().Completions()
2015-03-04 07:57:23 +00:00
}
2017-09-08 02:03:12 +00:00
func (c *OperatorUnsealCommand) Run(args []string) int {
2017-09-05 04:05:27 +00:00
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
2015-03-04 07:57:23 +00:00
return 1
}
2017-09-05 04:05:27 +00:00
unsealKey := ""
args = f.Args()
switch len(args) {
case 0:
// We will prompt for the unseal key later
2017-09-05 04:05:27 +00:00
case 1:
unsealKey = strings.TrimSpace(args[0])
default:
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
return 1
2015-03-13 19:58:21 +00:00
}
2017-09-05 04:05:27 +00:00
client, err := c.Client()
2015-05-19 07:34:18 +00:00
if err != nil {
2017-09-05 04:05:27 +00:00
c.UI.Error(err.Error())
2015-05-19 07:34:18 +00:00
return 2
}
2017-09-05 04:05:27 +00:00
if c.flagReset {
status, err := client.Sys().ResetUnsealProcess()
if err != nil {
c.UI.Error(fmt.Sprintf("Error resetting unseal process: %s", err))
return 2
}
2017-09-21 17:38:39 +00:00
return OutputSealStatus(c.UI, client, status)
2015-05-19 07:34:18 +00:00
}
2017-09-05 04:05:27 +00:00
if unsealKey == "" {
// Override the output
writer := (io.Writer)(os.Stdout)
if c.testOutput != nil {
writer = c.testOutput
}
2017-09-05 04:05:27 +00:00
2017-09-21 17:38:39 +00:00
fmt.Fprintf(writer, "Unseal Key (will be hidden): ")
2017-09-05 04:05:27 +00:00
value, err := password.Read(os.Stdin)
fmt.Fprintf(writer, "\n")
if err != nil {
c.UI.Error(wrapAtLength(fmt.Sprintf("An error occurred attempting to "+
"ask for an unseal key. The raw error message is shown below, but "+
"usually this is because you attempted to pipe a value into the "+
"unseal command or you are executing outside of a terminal (tty). "+
"You should run the unseal command from a terminal for maximum "+
"security. If this is not an option, the unseal key can be provided "+
"as the first argument to the unseal command. The raw error "+
2017-09-05 04:05:27 +00:00
"was:\n\n%s", err)))
return 1
2015-03-14 03:17:55 +00:00
}
2017-09-05 04:05:27 +00:00
unsealKey = strings.TrimSpace(value)
}
2018-10-23 06:34:02 +00:00
status, err := client.Sys().UnsealWithOptions(&api.UnsealOpts{
Key: unsealKey,
Migrate: c.flagMigrate,
})
2015-03-13 19:58:21 +00:00
if err != nil {
2017-09-05 04:05:27 +00:00
c.UI.Error(fmt.Sprintf("Error unsealing: %s", err))
return 2
2015-03-13 19:58:21 +00:00
}
2017-09-21 17:38:39 +00:00
return OutputSealStatus(c.UI, client, status)
2015-03-04 07:57:23 +00:00
}