From 06df7d03bf46063a292c03f863f33aa9779ab3bc Mon Sep 17 00:00:00 2001 From: Jeff Roche <82384784+jeff-roche@users.noreply.github.com> Date: Fri, 8 Jul 2022 11:09:41 -0400 Subject: [PATCH] feat: Cli secret (#10) * feat: command line secrets * chore: readme update --- README.md | 2 +- example.biome.yaml | 1 + go.mod | 3 ++- go.sum | 7 ++++-- src/lib/setters/cli_setter.go | 37 +++++++++++++++++++++++++++---- src/lib/setters/setter_helpers.go | 12 ++++++---- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3ab9712..21c6d7c 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ $ onstaging ./bin/ci/deploy-service.sh ``` ## Future Plans -- Allow CLI input to be a secret (for passwords) - Potentially switching to [cobra](https://github.com/spf13/cobra) for the cli +- :white_check_mark: Allow CLI input to be a secret (for passwords) - :white_check_mark: Allow inhereting from other biomes in the same file - :white_check_mark: Allow setting an environment variable from stdin - :white_check_mark: Implement goreleaser for binary building diff --git a/example.biome.yaml b/example.biome.yaml index a40482e..a8d9155 100644 --- a/example.biome.yaml +++ b/example.biome.yaml @@ -6,6 +6,7 @@ environment: # Additional environment vars to load in MY_USEFUL_ENV: "A value I need" CLI_ENV_VAR: # Get the variable from the CLI from_cli: true + is_secret: true # Specifies a CLI Secret (won't save to your cli history) MY_AWS_SECRET_ENV: secret_arn: "{{ARN}}" # Secrets manager ARN secret_json_key: "my_super_secret_key" # JSON key in the secret diff --git a/go.mod b/go.mod index 99bd520..83046d7 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/joho/godotenv v1.4.0 github.com/meltwater/dragoman v1.2.2 github.com/stretchr/testify v1.7.1 + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d gopkg.in/yaml.v3 v3.0.1 ) @@ -27,8 +28,8 @@ require ( github.com/kr/pretty v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.2.0 // indirect - golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/go.sum b/go.sum index 1fb7956..3b4992f 100644 --- a/go.sum +++ b/go.sum @@ -54,10 +54,13 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= -golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/lib/setters/cli_setter.go b/src/lib/setters/cli_setter.go index 67b4db4..8cc2976 100644 --- a/src/lib/setters/cli_setter.go +++ b/src/lib/setters/cli_setter.go @@ -6,9 +6,12 @@ import ( "io" "os" "strings" + + "golang.org/x/crypto/ssh/terminal" ) const CLI_ENVIRONMENT_SETTER_KEY = "from_cli" +const CLI_ENVIRONMENT_SECRET_SETTER_KEY = "is_secret" // CLIEnvironmentSetter will pull an env var from the provided io.Reader (stdin) type CLIEnvironmentSetter struct { @@ -16,15 +19,21 @@ type CLIEnvironmentSetter struct { Value string } -func NewCLIEnvironmentSetter(key string, rd io.Reader) (*CLIEnvironmentSetter, error) { +func NewCLIEnvironmentSetter(key string, rd io.Reader, isSecret bool) (*CLIEnvironmentSetter, error) { // Get the value from the io.Reader fmt.Printf("%s: ", key) - reader := bufio.NewReader(rd) - val, err := reader.ReadString('\n') + var val string + var err error + + if isSecret { + val, err = getSecretCliInput(rd) + } else { + val, err = getCliInput(rd) + } + if err != nil { return nil, err } - val = strings.Replace(val, "\n", "", -1) // Remove any newline characters // Save and return the setter return &CLIEnvironmentSetter{ @@ -36,3 +45,23 @@ func NewCLIEnvironmentSetter(key string, rd io.Reader) (*CLIEnvironmentSetter, e func (s CLIEnvironmentSetter) SetEnv() error { return os.Setenv(s.Key, s.Value) } + +func getCliInput(rd io.Reader) (string, error) { + reader := bufio.NewReader(rd) + val, err := reader.ReadString('\n') + if err != nil { + return "", err + } + val = strings.Replace(val, "\n", "", -1) // Remove any newline characters + + return val, nil +} + +func getSecretCliInput(rd io.Reader) (string, error) { + byteSecret, err := terminal.ReadPassword(0) + if err != nil { + return "", err + } + + return strings.Replace(string(byteSecret), "\n", "", -1), nil // Convert to string and remove any newline characters +} diff --git a/src/lib/setters/setter_helpers.go b/src/lib/setters/setter_helpers.go index 1c241e6..4968823 100644 --- a/src/lib/setters/setter_helpers.go +++ b/src/lib/setters/setter_helpers.go @@ -34,12 +34,16 @@ func getComplexSetter(key string, node map[string]interface{}) (EnvironmentSette } // CLI Input - if val, exists := node[CLI_ENVIRONMENT_SETTER_KEY]; exists { - if val.(bool) { - return NewCLIEnvironmentSetter(key, os.Stdin) + if val, exists := node[CLI_ENVIRONMENT_SETTER_KEY]; exists && val.(bool) { + var isSecret bool + + if _, exists := node[CLI_ENVIRONMENT_SECRET_SETTER_KEY]; exists { + isSecret = node[CLI_ENVIRONMENT_SECRET_SETTER_KEY].(bool) } else { - return nil, fmt.Errorf("invalid value for %s: %v", CLI_ENVIRONMENT_SETTER_KEY, val) + isSecret = false } + + return NewCLIEnvironmentSetter(key, os.Stdin, isSecret) } return nil, fmt.Errorf("unkown environment config for variable '%s'", key)