commit fdd1cd124a8bd3448d42398fcd67eb5611d82c79 Author: Knut Ahlers Date: Mon Jun 19 13:51:20 2017 +0200 Initial version Signed-off-by: Knut Ahlers diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc2bab1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vault-patch diff --git a/main.go b/main.go new file mode 100644 index 0000000..9ddaad9 --- /dev/null +++ b/main.go @@ -0,0 +1,106 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/Luzifer/rconfig" + log "github.com/Sirupsen/logrus" + "github.com/hashicorp/vault/api" + kvbuilder "github.com/hashicorp/vault/helper/kv-builder" + homedir "github.com/mitchellh/go-homedir" +) + +var ( + cfg struct { + LogLevel string `flag:"log-level" default:"info" description:"Verbosity of logs to use (debug, info, warning, error, ...)"` + VaultAddress string `flag:"vault-addr" env:"VAULT_ADDR" default:"https://127.0.0.1:8200" description:"Vault API address"` + VaultToken string `flag:"vault-token" env:"VAULT_TOKEN" vardefault:"vault-token" description:"Specify a token to use instead of app-id auth"` + VersionAndExit bool `flag:"version" default:"false" description:"Print program version and exit"` + } + + version = "dev" +) + +func vaultTokenFromDisk() string { + vf, err := homedir.Expand("~/.vault-token") + if err != nil { + return "" + } + + data, err := ioutil.ReadFile(vf) + if err != nil { + return "" + } + + return string(data) +} + +func loadConfig() error { + rconfig.SetVariableDefaults(map[string]string{ + "vault-token": vaultTokenFromDisk(), + }) + if err := rconfig.Parse(&cfg); err != nil { + return err + } + + if cfg.VersionAndExit { + fmt.Printf("vault-patch %s\n", version) + os.Exit(0) + } + + if logLevel, err := log.ParseLevel(cfg.LogLevel); err == nil { + log.SetLevel(logLevel) + } else { + return fmt.Errorf("Unable to parse log level: %s", err) + } + + return nil +} + +func main() { + if err := loadConfig(); err != nil { + log.Fatalf("Unable to load CLI config: %s", err) + } + + if len(rconfig.Args()) < 2 { + log.Fatalf("Usage: vault-patch [options] path data") + } + + client, err := api.NewClient(&api.Config{ + Address: cfg.VaultAddress, + }) + if err != nil { + log.Fatalf("Unable to create Vault client: %s", err) + } + + client.SetToken(cfg.VaultToken) + + key := rconfig.Args()[1] + + s, err := client.Logical().Read(key) + if err != nil || s == nil { + log.Fatalf("Could not read key %q from vault: %s", key, err) + } + + data := s.Data + if data == nil { + data = make(map[string]interface{}) + } + + builder := kvbuilder.Builder{Stdin: os.Stdin} + if err := builder.Add(rconfig.Args()[2:len(rconfig.Args())]...); err != nil { + log.Fatalf("Unable to parse data: %s", err) + } + + for k, v := range builder.Map() { + data[k] = v + } + + if _, err := client.Logical().Write(key, data); err != nil { + log.Fatalf("Could not write data to key %q: %s", key, err) + } + + log.Printf("Data successfully written to key %q", key) +}