Change behavior of `-token` and `-password` to support env/file only (#2327)

* Revert "Remove `-token` flag (#2303)"

This reverts commit 65cff995d7.

* Change behavior of -token

* Add use of MustParsePath

* Update changelog

* Use errors.Is
pull/2333/head api/v0.0.27
Jeff Mitchell 4 years ago committed by GitHub
parent ddb7ec7b49
commit fe2ee7ef4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -37,10 +37,17 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
* Credential stores: Static-type credential stores/credentials now use typed
prefixes for any newly-created resources. Existing resources will not be
affected. ([PR](https://github.com/hashicorp/boundary/pull/2256))
* Removal of `-token` flag from CLI: Passing a token this way can reveal the
token to any user or service that can look at process information. CLI users
can use the keyring integration or `BOUNDARY_TOKEN` env var.
([PR](https://github.com/hashicorp/boundary/pull/2303))
* Change of behavior on `-token` flag in CLI: Passing a token this way can
reveal the token to any user or service that can look at process information.
This flag must now reference a file on disk or an env var. Direct usage of the
`BOUNDARY_TOKEN` env var is also deprecated as it can show up in environment
information; the `env://` format now supported by the `-token` flag causes the
Boundary process to read it instead of the shell so is safer.
([PR](https://github.com/hashicorp/boundary/pull/2327))
* Change of behavior on `-password` flag in CLI: The same change made above for
`-token` has also been applied to `-password` or, for supporting resource
types, `-current-password` and `-new-password`.
([PR](https://github.com/hashicorp/boundary/pull/2327))
## 0.9.1 (2022/07/06)

@ -40,7 +40,7 @@ require (
github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.1
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.4
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7
github.com/hashicorp/go-secure-stdlib/password v0.1.1
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.1
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1

@ -713,6 +713,8 @@ github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtf
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2 h1:Tz6v3Jb2DRnDCfifRSjYKG0m8dLdNq6bcDkB41en7nw=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.2/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.1 h1:s47ax4xEIStj1YV7TRz6zS8LlNrTU86aEhL8pfSOG4U=

@ -21,6 +21,7 @@ import (
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
configutil "github.com/hashicorp/go-secure-stdlib/configutil/v2"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
"github.com/mitchellh/cli"
"github.com/pkg/errors"
@ -93,6 +94,7 @@ type Command struct {
flagTLSInsecure bool
flagFormat string
FlagToken string
FlagTokenName string
FlagKeyringType string
FlagRecoveryConfig string
@ -273,6 +275,22 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) {
c.client.SetRecoveryKmsWrapper(wrapper)
case c.FlagToken != "":
token, err := parseutil.MustParsePath(c.FlagToken)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
return nil, errors.New("Token flag must be used with env:// or file:// syntax")
default:
return nil, fmt.Errorf("error parsing token flag: %w", err)
}
c.client.SetToken(token)
case c.FlagToken == "" && os.Getenv(envToken) != "":
// Backwards compat: allow reading from existing BOUNDARY_TOKEN env var
c.UI.Warn(`Direct usage of BOUNDARY_TOKEN env var is deprecated; please use "-token env://<env var nameL>" format, e.g. "-token env://BOUNDARY_TOKEN" to specify an env var to use.`)
c.client.SetToken(os.Getenv(envToken))
case c.client.Token() == "" && strings.ToLower(c.FlagKeyringType) != "none":
keyringType, tokenName, err := c.DiscoverKeyringTokenInfo()
if err != nil {
@ -393,6 +411,13 @@ func (c *Command) FlagSet(bit FlagSetBit) *FlagSets {
Usage: `The type of keyring to use. Defaults to "auto" which will use the Windows credential manager, OSX keychain, or cross-platform password store depending on platform. Set to "none" to disable keyring functionality. Available types, depending on platform, are: "wincred", "keychain", "pass", and "secret-service".`,
})
f.StringVar(&StringVar{
Name: "token",
Target: &c.FlagToken,
EnvVar: envToken,
Usage: `A URL pointing to a file on disk (file://) from which a token will be read or an env var (env://) from which the token will be read. Overrides the "token-name" parameter.`,
})
f.StringVar(&StringVar{
Name: "recovery-config",
Target: &c.FlagRecoveryConfig,

@ -1,6 +1,7 @@
package accountscmd
import (
"errors"
"fmt"
"os"
"strings"
@ -141,8 +142,13 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]accounts.O
c.flagPassword = strings.TrimSpace(value)
default:
password, err := parseutil.ParsePath(c.flagPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
password, err := parseutil.MustParsePath(c.flagPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Password flag must be used with env:// or file:// syntax or left empty for an interactive prompt")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing password flag: %v", err))
return false
}
@ -164,8 +170,13 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]accounts.O
c.flagCurrentPassword = strings.TrimSpace(value)
default:
password, err := parseutil.ParsePath(c.flagCurrentPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
password, err := parseutil.MustParsePath(c.flagCurrentPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Current password flag must be used with env:// or file:// syntax or left empty for an interactive prompt")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing current password flag: %v", err))
return false
}
@ -196,8 +207,13 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]accounts.O
c.flagNewPassword = strings.TrimSpace(value)
default:
password, err := parseutil.ParsePath(c.flagNewPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
password, err := parseutil.MustParsePath(c.flagNewPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("New password flag must be used with env:// or file:// syntax or left empty for an interactive prompt")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing new password flag: %v", err))
return false
}

@ -1,6 +1,7 @@
package accountscmd
import (
"errors"
"fmt"
"os"
"strings"
@ -73,7 +74,7 @@ func extraPasswordFlagsFuncImpl(c *PasswordCommand, set *base.FlagSets, f *base.
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If blank, the command will prompt for the password to be entered interactively in a non-echoing way. Otherwise, this can refer to a file on disk (file://) from which a password will be read; an env var (env://) from which the password will be read; or a string containing the password.",
Usage: "The password for the account. If blank, the command will prompt for the password to be entered interactively in a non-echoing way. Otherwise, this can refer to a file on disk (file://) from which a password will be read or an env var (env://) from which the password will be read.",
})
}
}
@ -117,8 +118,13 @@ func extraPasswordFlagsHandlingFuncImpl(c *PasswordCommand, _ *base.FlagSets, op
*opts = append(*opts, accounts.WithPasswordAccountPassword(strings.TrimSpace(value)))
default:
password, err := parseutil.ParsePath(c.flagPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
password, err := parseutil.MustParsePath(c.flagPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Password flag must be used with env:// or file:// syntax or left empty for an interactive prompt")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing password flag: %v", err))
return false
}

@ -64,7 +64,7 @@ func (c *PasswordCommand) Flags() *base.FlagSets {
Name: "password",
Target: &c.flagPassword,
EnvVar: envPassword,
Usage: "The password associated with the login name. If blank, the command will prompt for the password to be entered interactively in a non-echoing way. Otherwise, this can refer to a file on disk (file://) from which a password will be read; an env var (env://) from which the password will be read; or a string containing the password.",
Usage: "The password associated with the login name. If blank, the command will prompt for the password to be entered interactively in a non-echoing way. Otherwise, this can refer to a file on disk (file://) from which a password will be read or an env var (env://) from which the password will be read.",
})
f.StringVar(&base.StringVar{
@ -114,8 +114,13 @@ func (c *PasswordCommand) Run(args []string) int {
c.flagPassword = strings.TrimSpace(value)
default:
password, err := parseutil.ParsePath(c.flagPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
password, err := parseutil.MustParsePath(c.flagPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Password flag must be used with env:// or file:// syntax or left empty for an interactive prompt")
return base.CommandUserError
default:
c.UI.Error(fmt.Sprintf("Error parsing password flag: %v", err))
return base.CommandUserError
}

@ -1,6 +1,9 @@
package credentialscmd
import (
"errors"
"fmt"
"github.com/hashicorp/boundary/api/credentials"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/go-secure-stdlib/parseutil"
@ -58,9 +61,14 @@ func extraSshPrivateKeyFlagHandlingFuncImpl(c *SshPrivateKeyCommand, _ *base.Fla
switch c.flagPrivateKey {
case "":
default:
privateKey, err := parseutil.ParsePath(c.flagPrivateKey)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
c.UI.Error("Error parsing private key flag: " + err.Error())
privateKey, err := parseutil.MustParsePath(c.flagPrivateKey)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Private key flag must be used with env:// or file:// syntax")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing private key flag: %v", err))
return false
}
*opts = append(*opts, credentials.WithSshPrivateKeyCredentialPrivateKey(privateKey))

@ -1,6 +1,9 @@
package credentialscmd
import (
"errors"
"fmt"
"github.com/hashicorp/boundary/api/credentials"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/go-secure-stdlib/parseutil"
@ -43,7 +46,7 @@ func extraUsernamePasswordFlagsFuncImpl(c *UsernamePasswordCommand, set *base.Fl
f.StringVar(&base.StringVar{
Name: passwordFlagName,
Target: &c.flagPassword,
Usage: "The password associated with the credential. This can be the value itself, refer to a file on disk (file://) from which the value will be read, or an env var (env://) from which the value will be read.",
Usage: "The password associated with the credential. This can be a file on disk (file://) from which the value will be read, or an env var (env://) from which the value will be read.",
})
}
}
@ -58,9 +61,14 @@ func extraUsernamePasswordFlagHandlingFuncImpl(c *UsernamePasswordCommand, _ *ba
switch c.flagPassword {
case "":
default:
password, err := parseutil.ParsePath(c.flagPassword)
if err != nil && err.Error() != parseutil.ErrNotAUrl.Error() {
c.UI.Error("Error parsing password flag: " + err.Error())
password, err := parseutil.MustParsePath(c.flagPassword)
switch {
case err == nil:
case errors.Is(err, parseutil.ErrNotParsed):
c.UI.Error("Password flag must be used with env:// or file:// syntax")
return false
default:
c.UI.Error(fmt.Sprintf("Error parsing password flag: %v", err))
return false
}
*opts = append(*opts, credentials.WithUsernamePasswordCredentialPassword(password))

Loading…
Cancel
Save