func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) { mount, ok := m["mount"] if !ok { mount = "ldap" } username, ok := m["username"] if !ok { return "", fmt.Errorf("'username' var must be set") } password, ok := m["password"] if !ok { fmt.Printf("Password (will be hidden): ") var err error password, err = pwd.Read(os.Stdin) fmt.Println() if err != nil { return "", err } } path := fmt.Sprintf("auth/%s/login/%s", mount, username) secret, err := c.Logical().Write(path, map[string]interface{}{ "password": password, }) if err != nil { return "", err } if secret == nil { return "", fmt.Errorf("empty response from credential provider") } return secret.Auth.ClientToken, nil }
func (h *tokenAuthHandler) Auth(*api.Client, map[string]string) (string, error) { token := h.Token if token == "" { var err error // No arguments given, read the token from user input fmt.Printf("Token (will be hidden): ") token, err = password.Read(os.Stdin) fmt.Printf("\n") if err != nil { return "", fmt.Errorf( "Error attempting to ask for token. The raw error message\n"+ "is shown below, but the most common reason for this error is\n"+ "that you attempted to pipe a value into auth. If you want to\n"+ "pipe the token, please pass '-' as the token argument.\n\n"+ "Raw error: %s", err) } } if token == "" { return "", fmt.Errorf( "A token must be passed to auth. Please view the help\n" + "for more information.") } return token, nil }
func (c *UnsealCommand) Run(args []string) int { var reset bool flags := c.Meta.FlagSet("unseal", FlagSetDefault) flags.BoolVar(&reset, "reset", false, "") flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } client, err := c.Client() if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing client: %s", err)) return 2 } args = flags.Args() value := c.Key if len(args) > 0 { value = args[0] } if value == "" { fmt.Printf("Key (will be hidden): ") value, err = password.Read(os.Stdin) fmt.Printf("\n") if err != nil { c.Ui.Error(fmt.Sprintf( "Error attempting to ask for password. The raw error message\n"+ "is shown below, but the most common reason for this error is\n"+ "that you attempted to pipe a value into unseal or you're\n"+ "executing `vault unseal` from outside of a terminal.\n\n"+ "You should use `vault unseal` from a terminal for maximum\n"+ "security. If this isn't an option, the unseal key can be passed\n"+ "in using the first parameter.\n\n"+ "Raw error: %s", err)) return 1 } } status, err := client.Sys().Unseal(strings.TrimSpace(value)) if err != nil { c.Ui.Error(fmt.Sprintf( "Error attempting unseal: %s", err)) return 1 } c.Ui.Output(fmt.Sprintf( "Sealed: %v\n"+ "Key Shares: %d\n"+ "Key Threshold: %d\n"+ "Unseal Progress: %d", status.Sealed, status.N, status.T, status.Progress, )) return 0 }
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) { var data struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` Mount string `mapstructure:"mount"` Method string `mapstructure:"method"` Passcode string `mapstructure:"passcode"` } if err := mapstructure.WeakDecode(m, &data); err != nil { return "", err } if data.Username == "" { return "", fmt.Errorf("'username' must be specified") } if data.Password == "" { fmt.Printf("Password (will be hidden): ") password, err := pwd.Read(os.Stdin) fmt.Println() if err != nil { return "", err } data.Password = password } if data.Mount == "" { data.Mount = "userpass" } options := map[string]interface{}{ "password": data.Password, } if data.Method != "" { options["method"] = data.Method } if data.Passcode != "" { options["passcode"] = data.Passcode } path := fmt.Sprintf("auth/%s/login/%s", data.Mount, data.Username) secret, err := c.Logical().Write(path, options) if err != nil { return "", err } if secret == nil { return "", fmt.Errorf("empty response from credential provider") } return secret.Auth.ClientToken, nil }
func (c *RekeyCommand) Run(args []string) int { var init, cancel, status, delete, retrieve, backup bool var shares, threshold int var nonce string var pgpKeys pgpkeys.PubKeyFilesFlag flags := c.Meta.FlagSet("rekey", FlagSetDefault) flags.BoolVar(&init, "init", false, "") flags.BoolVar(&cancel, "cancel", false, "") flags.BoolVar(&status, "status", false, "") flags.BoolVar(&delete, "delete", false, "") flags.BoolVar(&retrieve, "retrieve", false, "") flags.BoolVar(&backup, "backup", false, "") flags.IntVar(&shares, "key-shares", 5, "") flags.IntVar(&threshold, "key-threshold", 3, "") flags.StringVar(&nonce, "nonce", "", "") flags.Var(&pgpKeys, "pgp-keys", "") flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } if nonce != "" { c.Nonce = nonce } client, err := c.Client() if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing client: %s", err)) return 2 } // Check if we are running doing any restricted variants switch { case init: return c.initRekey(client, shares, threshold, pgpKeys, backup) case cancel: return c.cancelRekey(client) case status: return c.rekeyStatus(client) case retrieve: return c.rekeyRetrieveStored(client) case delete: return c.rekeyDeleteStored(client) } // Check if the rekey is started rekeyStatus, err := client.Sys().RekeyStatus() if err != nil { c.Ui.Error(fmt.Sprintf("Error reading rekey status: %s", err)) return 1 } // Start the rekey process if not started if !rekeyStatus.Started { err := client.Sys().RekeyInit(&api.RekeyInitRequest{ SecretShares: shares, SecretThreshold: threshold, PGPKeys: pgpKeys, }) if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err)) return 1 } rekeyStatus, err = client.Sys().RekeyStatus() if err != nil { c.Ui.Error(fmt.Sprintf("Error reading rekey status: %s", err)) return 1 } c.Nonce = rekeyStatus.Nonce } shares = rekeyStatus.N threshold = rekeyStatus.T serverNonce := rekeyStatus.Nonce // Get the unseal key args = flags.Args() key := c.Key if len(args) > 0 { key = args[0] } if key == "" { c.Nonce = serverNonce fmt.Printf("Rekey operation nonce: %s\n", serverNonce) fmt.Printf("Key (will be hidden): ") key, err = password.Read(os.Stdin) fmt.Printf("\n") if err != nil { c.Ui.Error(fmt.Sprintf( "Error attempting to ask for password. The raw error message\n"+ "is shown below, but the most common reason for this error is\n"+ "that you attempted to pipe a value into unseal or you're\n"+ "executing `vault rekey` from outside of a terminal.\n\n"+ "You should use `vault rekey` from a terminal for maximum\n"+ "security. If this isn't an option, the unseal key can be passed\n"+ "in using the first parameter.\n\n"+ "Raw error: %s", err)) return 1 } } // Provide the key, this may potentially complete the update result, err := client.Sys().RekeyUpdate(strings.TrimSpace(key), c.Nonce) if err != nil { c.Ui.Error(fmt.Sprintf("Error attempting rekey update: %s", err)) return 1 } // If we are not complete, then dump the status if !result.Complete { return c.rekeyStatus(client) } // Provide the keys for i, key := range result.Keys { if len(result.PGPFingerprints) > 0 { c.Ui.Output(fmt.Sprintf("Key %d fingerprint: %s; value: %s", i+1, result.PGPFingerprints[i], key)) } else { c.Ui.Output(fmt.Sprintf("Key %d: %s", i+1, key)) } } c.Ui.Output(fmt.Sprintf("\nOperation nonce: %s", result.Nonce)) if len(result.PGPFingerprints) > 0 && result.Backup { c.Ui.Output(fmt.Sprintf( "\n" + "The encrypted unseal keys have been backed up to \"core/unseal-keys\n" + "in your physical backend. It is your responsibility to remove these\n" + "if and when desired.", )) } c.Ui.Output(fmt.Sprintf( "\n"+ "Vault rekeyed with %d keys and a key threshold of %d. Please\n"+ "securely distribute the above keys. When the Vault is re-sealed,\n"+ "restarted, or stopped, you must provide at least %d of these keys\n"+ "to unseal it again.\n\n"+ "Vault does not store the master key. Without at least %d keys,\n"+ "your Vault will remain permanently sealed.", shares, threshold, threshold, threshold, )) return 0 }
func (i *cliUi) Input(opts *ui.InputOpts) (string, error) { // 如何设置了环境变量,我们就不询问提示input if value := opts.EnvVarValue(); value != "" { return value, nil } r := i.Reader w := i.Writer if r == nil { r = defaultInputReader } if w == nil { w = defaultInputWriter } if r == nil { r = os.Stdin } if w == nil { w = os.Stdout } // 确保我们只在第一次询问input.Terraform应该确保这个 // 但是不会破坏验证 i.l.Lock() defer i.l.Unlock() // 如果终止,那么就不询问input if i.interrupted { return "", errors.New("中断") } // 监听中断操作,那么就不再询问input sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) defer signal.Stop(sigCh) // 格式化询问输出 var buf bytes.Buffer buf.WriteString("[reset]") buf.WriteString(fmt.Sprintf("[bold]%s[reset]\n", opts.Query)) if opts.Description != "" { s := bufio.NewScanner(strings.NewReader(opts.Description)) for s.Scan() { buf.WriteString(fmt.Sprintf(" %s\n", s.Text())) } buf.WriteString("\n") } if opts.Default != "" { buf.WriteString(" [bold]Default:[reset] ") buf.WriteString(opts.Default) buf.WriteString("\n") } buf.WriteString(" [bold]输入一个值:[reset] ") // 询问用户输入 if _, err := fmt.Fprint(w, ui.Colorize(buf.String())); err != nil { return "", err } // 监听goroutine输入。这允许我们中断 result := make(chan string, 1) if opts.Hide { f, ok := r.(*os.File) if !ok { return "", fmt.Errorf("必须读取一个文件") } line, err := password.Read(f) if err != nil { return "", err } result <- line } else { go func() { var line string if _, err := fmt.Fscanln(r, &line); err != nil { log.Printf("[ERR] UIInput扫描错误: %s", err) } result <- line }() } select { case line := <-result: fmt.Fprint(w, "\n") if line == "" { line = opts.Default } return line, nil case <-sigCh: // 新起一行 fmt.Fprintln(w) // Mark that we were interrupted so future Ask calls fail. i.interrupted = true return "", errors.New("中断") } }
func (c *RekeyCommand) Run(args []string) int { var init, cancel, status bool var shares, threshold int var pgpKeys pgpkeys.PubKeyFilesFlag flags := c.Meta.FlagSet("rekey", FlagSetDefault) flags.BoolVar(&init, "init", false, "") flags.BoolVar(&cancel, "cancel", false, "") flags.BoolVar(&status, "status", false, "") flags.IntVar(&shares, "key-shares", 5, "") flags.IntVar(&threshold, "key-threshold", 3, "") flags.Var(&pgpKeys, "pgp-keys", "") flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } client, err := c.Client() if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing client: %s", err)) return 2 } // Check if we are running doing any restricted variants if init { return c.initRekey(client, shares, threshold, pgpKeys) } else if cancel { return c.cancelRekey(client) } else if status { return c.rekeyStatus(client) } // Check if the rekey is started rekeyStatus, err := client.Sys().RekeyStatus() if err != nil { c.Ui.Error(fmt.Sprintf("Error reading rekey status: %s", err)) return 1 } // Start the rekey process if not started if !rekeyStatus.Started { err := client.Sys().RekeyInit(&api.RekeyInitRequest{ SecretShares: shares, SecretThreshold: threshold, PGPKeys: pgpKeys, }) if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err)) return 1 } } else { shares = rekeyStatus.N threshold = rekeyStatus.T c.Ui.Output(fmt.Sprintf( "Rekey already in progress\n"+ "Key Shares: %d\n"+ "Key Threshold: %d\n", shares, threshold, )) } // Get the unseal key args = flags.Args() value := c.Key if len(args) > 0 { value = args[0] } if value == "" { fmt.Printf("Key (will be hidden): ") value, err = password.Read(os.Stdin) fmt.Printf("\n") if err != nil { c.Ui.Error(fmt.Sprintf( "Error attempting to ask for password. The raw error message\n"+ "is shown below, but the most common reason for this error is\n"+ "that you attempted to pipe a value into unseal or you're\n"+ "executing `vault rekey` from outside of a terminal.\n\n"+ "You should use `vault rekey` from a terminal for maximum\n"+ "security. If this isn't an option, the unseal key can be passed\n"+ "in using the first parameter.\n\n"+ "Raw error: %s", err)) return 1 } } // Provide the key, this may potentially complete the update result, err := client.Sys().RekeyUpdate(strings.TrimSpace(value)) if err != nil { c.Ui.Error(fmt.Sprintf("Error attempting rekey update: %s", err)) return 1 } // If we are not complete, then dump the status if !result.Complete { return c.rekeyStatus(client) } // Provide the keys for i, key := range result.Keys { c.Ui.Output(fmt.Sprintf("Key %d: %s", i+1, key)) } c.Ui.Output(fmt.Sprintf( "\n"+ "Vault rekeyed with %d keys and a key threshold of %d. Please\n"+ "securely distribute the above keys. When the Vault is re-sealed,\n"+ "restarted, or stopped, you must provide at least %d of these keys\n"+ "to unseal it again.\n\n"+ "Vault does not store the master key. Without at least %d keys,\n"+ "your Vault will remain permanently sealed.", shares, threshold, threshold, threshold, )) return 0 }
func (c *GenerateRootCommand) Run(args []string) int { var init, cancel, status, genotp bool var nonce, decode, otp, pgpKey string var pgpKeyArr pgpkeys.PubKeyFilesFlag flags := c.Meta.FlagSet("generate-root", FlagSetDefault) flags.BoolVar(&init, "init", false, "") flags.BoolVar(&cancel, "cancel", false, "") flags.BoolVar(&status, "status", false, "") flags.BoolVar(&genotp, "genotp", false, "") flags.StringVar(&decode, "decode", "", "") flags.StringVar(&otp, "otp", "", "") flags.StringVar(&nonce, "nonce", "", "") flags.Var(&pgpKeyArr, "pgp-key", "") flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } if genotp { buf := make([]byte, 16) readLen, err := rand.Read(buf) if err != nil { c.Ui.Error(fmt.Sprintf("Error reading random bytes: %s", err)) return 1 } if readLen != 16 { c.Ui.Error(fmt.Sprintf("Read %d bytes when we should have read 16", readLen)) return 1 } c.Ui.Output(fmt.Sprintf("OTP: %s", base64.StdEncoding.EncodeToString(buf))) return 0 } if len(decode) > 0 { if len(otp) == 0 { c.Ui.Error("Both the value to decode and the OTP must be passed in") return 1 } return c.decode(decode, otp) } client, err := c.Client() if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing client: %s", err)) return 2 } // Check if the root generation is started rootGenerationStatus, err := client.Sys().GenerateRootStatus() if err != nil { c.Ui.Error(fmt.Sprintf("Error reading root generation status: %s", err)) return 1 } // If we are initing, or if we are not started but are not running a // special function, check otp and pgpkey checkOtpPgp := false switch { case init: checkOtpPgp = true case cancel: case status: case genotp: case len(decode) != 0: case rootGenerationStatus.Started: default: checkOtpPgp = true } if checkOtpPgp { switch { case len(otp) == 0 && (pgpKeyArr == nil || len(pgpKeyArr) == 0): c.Ui.Error(c.Help()) return 1 case len(otp) != 0 && pgpKeyArr != nil && len(pgpKeyArr) != 0: c.Ui.Error(c.Help()) return 1 case len(otp) != 0: err := c.verifyOTP(otp) if err != nil { c.Ui.Error(fmt.Sprintf("Error verifying the provided OTP: %s", err)) return 1 } case pgpKeyArr != nil: if len(pgpKeyArr) != 1 { c.Ui.Error("Could not parse PGP key") return 1 } if len(pgpKeyArr[0]) == 0 { c.Ui.Error("Got an empty PGP key") return 1 } pgpKey = pgpKeyArr[0] default: panic("unreachable case") } } if nonce != "" { c.Nonce = nonce } // Check if we are running doing any restricted variants switch { case init: return c.initGenerateRoot(client, otp, pgpKey) case cancel: return c.cancelGenerateRoot(client) case status: return c.rootGenerationStatus(client) } // Start the root generation process if not started if !rootGenerationStatus.Started { err = client.Sys().GenerateRootInit(otp, pgpKey) if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing root generation: %s", err)) return 1 } rootGenerationStatus, err = client.Sys().GenerateRootStatus() if err != nil { c.Ui.Error(fmt.Sprintf("Error reading root generation status: %s", err)) return 1 } c.Nonce = rootGenerationStatus.Nonce } serverNonce := rootGenerationStatus.Nonce // Get the unseal key args = flags.Args() key := c.Key if len(args) > 0 { key = args[0] } if key == "" { c.Nonce = serverNonce fmt.Printf("Root generation operation nonce: %s\n", serverNonce) fmt.Printf("Key (will be hidden): ") key, err = password.Read(os.Stdin) fmt.Printf("\n") if err != nil { c.Ui.Error(fmt.Sprintf( "Error attempting to ask for password. The raw error message\n"+ "is shown below, but the most common reason for this error is\n"+ "that you attempted to pipe a value into unseal or you're\n"+ "executing `vault generate-root` from outside of a terminal.\n\n"+ "You should use `vault generate-root` from a terminal for maximum\n"+ "security. If this isn't an option, the unseal key can be passed\n"+ "in using the first parameter.\n\n"+ "Raw error: %s", err)) return 1 } } // Provide the key, this may potentially complete the update statusResp, err := client.Sys().GenerateRootUpdate(strings.TrimSpace(key), c.Nonce) if err != nil { c.Ui.Error(fmt.Sprintf("Error attempting generate-root update: %s", err)) return 1 } c.dumpStatus(statusResp) return 0 }
func (i *cliUi) Input(opts *ui.InputOpts) (string, error) { // If any of the configured EnvVars are set, we don't ask for input. if value := opts.EnvVarValue(); value != "" { return value, nil } r := i.Reader w := i.Writer if r == nil { r = defaultInputReader } if w == nil { w = defaultInputWriter } if r == nil { r = os.Stdin } if w == nil { w = os.Stdout } // Make sure we only ask for input once at a time. Terraform // should enforce this, but it doesn't hurt to verify. i.l.Lock() defer i.l.Unlock() // If we're interrupted, then don't ask for input if i.interrupted { return "", errors.New("interrupted") } // Listen for interrupts so we can cancel the input ask sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) defer signal.Stop(sigCh) // Build the output format for asking var buf bytes.Buffer buf.WriteString("[reset]") buf.WriteString(fmt.Sprintf("[bold]%s[reset]\n", opts.Query)) if opts.Description != "" { s := bufio.NewScanner(strings.NewReader(opts.Description)) for s.Scan() { buf.WriteString(fmt.Sprintf(" %s\n", s.Text())) } buf.WriteString("\n") } if opts.Default != "" { buf.WriteString(" [bold]Default:[reset] ") buf.WriteString(opts.Default) buf.WriteString("\n") } buf.WriteString(" [bold]Enter a value:[reset] ") // Ask the user for their input if _, err := fmt.Fprint(w, ui.Colorize(buf.String())); err != nil { return "", err } // Listen for the input in a goroutine. This will allow us to // interrupt this if we are interrupted (SIGINT) result := make(chan string, 1) if opts.Hide { f, ok := r.(*os.File) if !ok { return "", fmt.Errorf("reader must be a file") } line, err := password.Read(f) if err != nil { return "", err } result <- line } else { go func() { var line string if _, err := fmt.Fscanln(r, &line); err != nil { log.Printf("[ERR] UIInput scan err: %s", err) } result <- line }() } select { case line := <-result: fmt.Fprint(w, "\n") if line == "" { line = opts.Default } return line, nil case <-sigCh: // Print a newline so that any further output starts properly // on a new line. fmt.Fprintln(w) // Mark that we were interrupted so future Ask calls fail. i.interrupted = true return "", errors.New("interrupted") } }