From 6450bcb8a43d997eef94103481b37bdf9273c1d9 Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Wed, 28 Nov 2018 20:25:11 +0100 Subject: [PATCH] [#2] Implement obfuscation of secrets in output #3 closes #3, fixes #2 --- main.go | 47 ++++++++++++++++++++++++++++++++++++++++++----- obfuscator.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 obfuscator.go diff --git a/main.go b/main.go index 7ba8438..b2d1ef8 100644 --- a/main.go +++ b/main.go @@ -6,12 +6,14 @@ import ( "os" "os/exec" "strings" + "sync" - "github.com/Luzifer/go_helpers/env" - "github.com/Luzifer/rconfig" log "github.com/Sirupsen/logrus" "github.com/hashicorp/vault/api" "github.com/mitchellh/go-homedir" + + "github.com/Luzifer/go_helpers/env" + "github.com/Luzifer/rconfig" ) var ( @@ -22,6 +24,7 @@ var ( } Export bool `flag:"export,e" default:"false" description:"Show export statements instead of running the command specified"` LogLevel string `flag:"log-level" default:"info" description:"Verbosity of logs to use (debug, info, warning, error, ...)"` + Obfuscate string `flag:"obfuscate,o" default:"asterisk" description:"Type of obfuscation (none, asterisk, hash, name)"` TokenAuth struct { Token string `flag:"vault-token" env:"VAULT_TOKEN" vardefault:"vault-token" description:"Specify a token to use instead of app-id auth"` } @@ -161,6 +164,8 @@ func main() { return } + obfuscate := prepareObfuscator(envData) + emap := env.ListToMap(os.Environ()) for k, v := range emap { if _, ok := envData[k]; !ok { @@ -169,11 +174,43 @@ func main() { } cmd := exec.Command(rconfig.Args()[1], rconfig.Args()[2:]...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Env = env.MapToList(envData) - if err := cmd.Run(); err != nil { + + stderr, err := cmd.StderrPipe() + if err != nil { + log.WithError(err).Fatal("Unable to get stderr pipe") + } + + stdout, err := cmd.StdoutPipe() + if err != nil { + log.WithError(err).Fatal("Unable to get stdout pipe") + } + + if err := cmd.Start(); err != nil { + log.WithError(err).Fatal("Unable to start command") + } + + wg := new(sync.WaitGroup) + wg.Add(2) + + go func() { + defer wg.Done() + if err := obfuscationTransport(stdout, os.Stdout, obfuscate); err != nil { + log.WithError(err).Error("Failed to obfuscate stdout") + } + }() + + go func() { + defer wg.Done() + if err := obfuscationTransport(stderr, os.Stderr, obfuscate); err != nil { + log.WithError(err).Error("Failed to obfuscate stderr") + } + }() + + wg.Wait() + + if err := cmd.Wait(); err != nil { log.Fatal("Command exitted unclean (code != 0)") } } diff --git a/obfuscator.go b/obfuscator.go new file mode 100644 index 0000000..0f3a8dd --- /dev/null +++ b/obfuscator.go @@ -0,0 +1,48 @@ +package main + +import ( + "bufio" + "crypto/sha256" + "fmt" + "io" + "strings" + + "github.com/pkg/errors" +) + +func prepareObfuscator(secrets map[string]string) func(string) string { + var prepare func(name, secret string) string + + switch cfg.Obfuscate { + case "asterisk": + prepare = func(name, secret string) string { return "****" } + + case "hash": + prepare = func(name, secret string) string { return fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(secret))) } + + case "name": + prepare = func(name, secret string) string { return name } + + default: + return func(in string) string { return in } + } + + replacements := []string{} + + for k, v := range secrets { + if k != "" && v != "" { + replacements = append(replacements, v, prepare(k, v)) + } + } + repl := strings.NewReplacer(replacements...) + + return func(in string) string { return repl.Replace(in) } +} + +func obfuscationTransport(in io.Reader, out io.Writer, obfuscate func(string) string) error { + s := bufio.NewScanner(in) + for s.Scan() { + fmt.Fprintln(out, obfuscate(s.Text())) + } + return errors.Wrapf(s.Err(), "Failed to scan in buffer") +}