Пример #1
1
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
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
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
}
Пример #5
0
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
}
Пример #6
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("中断")
	}
}
Пример #7
0
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
}
Пример #8
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
}
Пример #9
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")
	}
}