open-vault/command/operator_unseal.go

163 lines
4 KiB
Go
Raw Normal View History

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 master key to unseal a Vault server. Vault starts
in a sealed state. It cannot perform operations until it is unsealed. This
command accepts a portion of the master key (an "unseal key").
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
}