From 43eaa3f42cccfda79466e366efb4a0f4b6403b56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20Hedenstro=CC=88m?= <erik@hedenstroem.com>
Date: Sun, 18 Dec 2016 12:20:56 +0100
Subject: [PATCH] Added support for multiple platforms. Added vendoring. Added
 download command.

---
 .gitignore         |   3 +-
 .gitlab-ci.yml     |  32 +++++++--
 README.md          |  21 +++++-
 cmd/delete.go      |   4 ++
 cmd/download.go    |  36 ++++++++++
 cmd/read.go        |  10 ++-
 cmd/root.go        |   6 --
 cmd/version.go     |   4 ++
 cmd/write.go       |   4 ++
 vendor/vendor.json | 169 +++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 272 insertions(+), 17 deletions(-)
 create mode 100644 cmd/download.go
 create mode 100644 vendor/vendor.json

diff --git a/.gitignore b/.gitignore
index 495a93b..5f924b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,5 +24,6 @@ _testmain.go
 *.test
 *.prof
 
+vendor/*/
 .env
-vaultenv
\ No newline at end of file
+vaultenv
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c2d9da8..ce0224e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: registry.hedenstroem.com/gitlab/gitlab-builder-go:1.7.3
+image: registry.hedenstroem.com/gitlab/gitlab-builder-go:1.7
 
 before_script:
   - CI_PROJECT_HOST=gitlab.hedenstroem.com
@@ -15,25 +15,43 @@ stages:
 go build:
   stage: build
   script:
-    - go get -v -d ./...
+    - git describe --tags --long > vaultenv-version.txt
+    - govendor sync
     - go generate constant/version.go
-    - CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"'
+    - GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-darwin
+    - GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-linux-arm
+    - GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-linux-i386
+    - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-linux-amd64
+    - GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-windows.exe
+    - GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -tags netgo --ldflags '-extldflags "-static"' -o vaultenv-windows-x64.exe
   artifacts:
     paths:
-    - vaultenv
+    - vaultenv-version.txt
+    - vaultenv-darwin
+    - vaultenv-linux-arm
+    - vaultenv-linux-i386
+    - vaultenv-linux-amd64
+    - vaultenv-windows.exe
+    - vaultenv-windows-x64.exe
 
 upload to aws:
   stage: deploy
   only:
-    - master
+    - /^\d+[.]\d+[.]\d+$/
   script:
     - eval $(vaultenv read -s secret/gitlab-ci/s3)
-    - aws s3 cp vaultenv s3://s3.hedenstroem.com/utils/
+    - aws s3 cp vaultenv-version.txt s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-darwin s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-linux-arm s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-linux-i386 s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-linux-amd64 s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-windows.exe s3://s3.hedenstroem.com/utils/vault/
+    - aws s3 cp vaultenv-windows-x64.exe s3://s3.hedenstroem.com/utils/vault/
 
 trigger downstream:
   stage: trigger
   only:
-    - master
+    - /^\d+[.]\d+[.]\d+$/
   script:
     - gitlab_trigger_downstream
   when: manual
diff --git a/README.md b/README.md
index 431a267..9309d38 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,26 @@
 # Vault Environment Tool
 
-The following example sets up a policy with read-only access to secrets, and an 'lts' role that has a token ttl of 10 years.
+A small utility to export data from vault as environment variables or download as files.
 
+## Installation
+
+You can download one of the pre-compiled binaries from the list below.
+
+- [Mac](http://s3.hedenstroem.com/utils/vault/vaultenv-darwin)
+- [Linux (ARM)](http://s3.hedenstroem.com/utils/vault/vaultenv-linux-arm)
+- [Linux (32-bit)](http://s3.hedenstroem.com/utils/vault/vaultenv-linux-i386)
+- [Linux (64-bit)](http://s3.hedenstroem.com/utils/vault/vaultenv-linux-amd64)
+- [Windows (32-bit)](http://s3.hedenstroem.com/utils/vault/vaultenv-windows.exe)
+- [Windows (64-bit)](http://s3.hedenstroem.com/utils/vault/vaultenv-windows-x64.exe)
+
+## Usage
+```bash
+> vaultenv help
+```
+
+## Creating a read only token
+
+The following example sets up a policy with read-only access to secrets/env, and an 'lts' role that has a token ttl of 10 years.
 
 ```
 > vault policy-write secret-ro acl.hcl
diff --git a/cmd/delete.go b/cmd/delete.go
index 9750b13..d312bd3 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -24,3 +24,7 @@ var deleteCmd = &cobra.Command{
 		return
 	},
 }
+
+func init() {
+	RootCmd.AddCommand(deleteCmd)
+}
diff --git a/cmd/download.go b/cmd/download.go
new file mode 100644
index 0000000..9cd6812
--- /dev/null
+++ b/cmd/download.go
@@ -0,0 +1,36 @@
+package cmd
+
+import (
+	"encoding/base64"
+	"errors"
+
+	"gitlab.hedenstroem.com/go/vaultenv/vault"
+
+	"io/ioutil"
+
+	"github.com/spf13/cobra"
+)
+
+var downloadCmd = &cobra.Command{
+	Use:   "download [flags] path file",
+	Short: "download Short",
+	Long:  `download Long`,
+	RunE: func(cmd *cobra.Command, args []string) (err error) {
+		if len(args) != 2 {
+			return errors.New("Expected 2 arguments; path and file.")
+		}
+		data, err := vault.GetSecret(args[0])
+		if data != nil {
+			enc := data["file"]
+			b, err := base64.StdEncoding.DecodeString(enc.(string))
+			if err == nil {
+				err = ioutil.WriteFile(args[1], b, 0600)
+			}
+		}
+		return
+	},
+}
+
+func init() {
+	RootCmd.AddCommand(downloadCmd)
+}
diff --git a/cmd/read.go b/cmd/read.go
index 33cc960..a652661 100644
--- a/cmd/read.go
+++ b/cmd/read.go
@@ -12,9 +12,10 @@ import (
 	"strings"
 
 	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
 )
 
+var shellFormat bool
+
 var readCmd = &cobra.Command{
 	Use:   "read [flags] path",
 	Short: "read Short",
@@ -25,7 +26,7 @@ var readCmd = &cobra.Command{
 		}
 		data, err := vault.GetSecret(args[0])
 		if data != nil {
-			if viper.GetBool("shell") {
+			if shellFormat {
 				for k, v := range data {
 					qv := strconv.QuoteToASCII(v.(string))
 					qv = strings.Replace(qv, "'", "\\x27", -1)
@@ -40,3 +41,8 @@ var readCmd = &cobra.Command{
 		return
 	},
 }
+
+func init() {
+	RootCmd.AddCommand(readCmd)
+	readCmd.Flags().BoolVarP(&shellFormat, "shell", "s", false, "Format output for eval(...)")
+}
diff --git a/cmd/root.go b/cmd/root.go
index 4f7fa88..5a903eb 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -24,17 +24,11 @@ func Execute() {
 
 func init() {
 	cobra.OnInitialize(initEnv)
-	RootCmd.AddCommand(readCmd)
-	RootCmd.AddCommand(writeCmd)
-	RootCmd.AddCommand(deleteCmd)
-	RootCmd.AddCommand(versionCmd)
 	RootCmd.PersistentFlags().StringP("addr", "a", "http://127.0.0.1:8200", "Address to the vault server")
 	RootCmd.PersistentFlags().StringP("token", "t", "", "Vault access token")
-	readCmd.Flags().BoolP("shell", "s", false, "Format output for eval(...)")
 	viper.SetEnvPrefix("VAULT")
 	viper.BindPFlag("ADDR", RootCmd.PersistentFlags().Lookup("addr"))
 	viper.BindPFlag("TOKEN", RootCmd.PersistentFlags().Lookup("token"))
-	viper.BindPFlag("shell", readCmd.Flags().Lookup("shell"))
 }
 
 func initEnv() {
diff --git a/cmd/version.go b/cmd/version.go
index 5857844..f26af3e 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -15,3 +15,7 @@ var versionCmd = &cobra.Command{
 		fmt.Printf("Version: %s", constant.Version)
 	},
 }
+
+func init() {
+	RootCmd.AddCommand(versionCmd)
+}
diff --git a/cmd/write.go b/cmd/write.go
index 4c5fae4..99b2782 100644
--- a/cmd/write.go
+++ b/cmd/write.go
@@ -34,3 +34,7 @@ var writeCmd = &cobra.Command{
 		return
 	},
 }
+
+func init() {
+	RootCmd.AddCommand(writeCmd)
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
new file mode 100644
index 0000000..6b4a8ed
--- /dev/null
+++ b/vendor/vendor.json
@@ -0,0 +1,169 @@
+{
+	"comment": "",
+	"ignore": "test",
+	"package": [
+		{
+			"checksumSHA1": "hveFTNQ9YEyYRs6SWuXM+XU9qRI=",
+			"path": "github.com/fsnotify/fsnotify",
+			"revision": "fd9ec7deca8bf46ecd2a795baaacf2b3a9be1197",
+			"revisionTime": "2016-10-26T20:31:22Z"
+		},
+		{
+			"checksumSHA1": "8OPDk+bKyRGJoKcS4QNw9F7dpE8=",
+			"path": "github.com/hashicorp/hcl",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "XQmjDva9JCGGkIecOgwtBEMCJhU=",
+			"path": "github.com/hashicorp/hcl/hcl/ast",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "croNloscHsjX87X+4/cKOURf1EY=",
+			"path": "github.com/hashicorp/hcl/hcl/parser",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "Zz4271B4Kc+rwwK7cbaRv7STfO8=",
+			"path": "github.com/hashicorp/hcl/hcl/scanner",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "/e0ULfQnGeUKiM1+iMnQhImo62k=",
+			"path": "github.com/hashicorp/hcl/hcl/strconv",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "c6yprzj06ASwCo18TtbbNNBHljA=",
+			"path": "github.com/hashicorp/hcl/hcl/token",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "138aCV5n8n7tkGYMsMVQQnnLq+0=",
+			"path": "github.com/hashicorp/hcl/json/parser",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "YdvFsNOMSWMLnY6fcliWQa0O5Fw=",
+			"path": "github.com/hashicorp/hcl/json/scanner",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "fNlXQCQEnb+B3k5UDL/r15xtSJY=",
+			"path": "github.com/hashicorp/hcl/json/token",
+			"revision": "7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0",
+			"revisionTime": "2016-11-22T02:11:24Z"
+		},
+		{
+			"checksumSHA1": "40vJyUB4ezQSn/NSadsKEOrudMc=",
+			"path": "github.com/inconshreveable/mousetrap",
+			"revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75",
+			"revisionTime": "2014-10-17T20:07:13Z"
+		},
+		{
+			"checksumSHA1": "ljZrmD7pmMXAkGNfp6IEzj31fY8=",
+			"path": "github.com/joho/godotenv",
+			"revision": "4ed13390c0acd2ff4e371e64d8b97c8954138243",
+			"revisionTime": "2015-09-07T01:02:28Z"
+		},
+		{
+			"checksumSHA1": "S6PDDQMYaKwLDIP/NsRYb4FRAqQ=",
+			"path": "github.com/magiconair/properties",
+			"revision": "0723e352fa358f9322c938cc2dadda874e9151a9",
+			"revisionTime": "2016-09-08T09:36:58Z"
+		},
+		{
+			"checksumSHA1": "UuXgD2dDojfS8AViUEe15gLIWZE=",
+			"path": "github.com/mitchellh/mapstructure",
+			"revision": "f3009df150dadf309fdee4a54ed65c124afad715",
+			"revisionTime": "2016-10-20T16:18:36Z"
+		},
+		{
+			"checksumSHA1": "8Y05Pz7onrQPcVWW6JStSsYRh6E=",
+			"path": "github.com/pelletier/go-buffruneio",
+			"revision": "df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d",
+			"revisionTime": "2016-01-24T19:35:03Z"
+		},
+		{
+			"checksumSHA1": "jIC6IQtpM2X84AUYISO/V7C9hQs=",
+			"path": "github.com/pelletier/go-toml",
+			"revision": "7cb988051d5045890cb91402a0b5fddc76c627bc",
+			"revisionTime": "2016-11-23T15:24:52Z"
+		},
+		{
+			"checksumSHA1": "f2mjcLDkc28ImTfmedA5kfcOzUw=",
+			"path": "github.com/spf13/afero",
+			"revision": "06b7e5f50606ecd49148a01a6008942d9b669217",
+			"revisionTime": "2016-11-09T00:09:53Z"
+		},
+		{
+			"checksumSHA1": "u6B0SEgZ/TUEfIvF6w/HnFVQbII=",
+			"path": "github.com/spf13/afero/mem",
+			"revision": "06b7e5f50606ecd49148a01a6008942d9b669217",
+			"revisionTime": "2016-11-09T00:09:53Z"
+		},
+		{
+			"checksumSHA1": "+mfjYfgvbP8vg0ubsMOw/iTloo8=",
+			"path": "github.com/spf13/cast",
+			"revision": "24b6558033ffe202bf42f0f3b870dcc798dd2ba8",
+			"revisionTime": "2016-11-16T01:33:54Z"
+		},
+		{
+			"checksumSHA1": "FZ0r4TzEy9UxXLkFVXFygApni4M=",
+			"path": "github.com/spf13/cobra",
+			"revision": "9495bc009a56819bdb0ddbc1a373e29c140bc674",
+			"revisionTime": "2016-11-16T13:20:53Z"
+		},
+		{
+			"checksumSHA1": "dkruahfhuLXXuyeCuRpsWlcRK+8=",
+			"path": "github.com/spf13/jwalterweatherman",
+			"revision": "33c24e77fb80341fe7130ee7c594256ff08ccc46",
+			"revisionTime": "2016-03-01T12:00:06Z"
+		},
+		{
+			"checksumSHA1": "GxPD7A0NjMDom1xte0mghkpzr0E=",
+			"path": "github.com/spf13/pflag",
+			"revision": "5ccb023bc27df288a957c5e994cd44fd19619465",
+			"revisionTime": "2016-10-24T13:13:51Z"
+		},
+		{
+			"checksumSHA1": "802GjFNHMmnFXEIkQ137ucUUacI=",
+			"path": "github.com/spf13/viper",
+			"revision": "651d9d916abc3c3d6a91a12549495caba5edffd2",
+			"revisionTime": "2016-10-29T21:33:52Z"
+		},
+		{
+			"checksumSHA1": "MlTI84eWAFvqeRgXxBtjRYHk1yQ=",
+			"path": "golang.org/x/sys/unix",
+			"revision": "30237cf4eefd639b184d1f2cb77a581ea0be8947",
+			"revisionTime": "2016-11-19T15:29:01Z"
+		},
+		{
+			"checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=",
+			"path": "golang.org/x/text/transform",
+			"revision": "b01949dc0793a9af5e4cb3fce4d42999e76e8ca1",
+			"revisionTime": "2016-11-03T07:49:12Z"
+		},
+		{
+			"checksumSHA1": "Vircurgvsnt4k26havmxPM67PUA=",
+			"path": "golang.org/x/text/unicode/norm",
+			"revision": "b01949dc0793a9af5e4cb3fce4d42999e76e8ca1",
+			"revisionTime": "2016-11-03T07:49:12Z"
+		},
+		{
+			"checksumSHA1": "12GqsW8PiRPnezDDy0v4brZrndM=",
+			"path": "gopkg.in/yaml.v2",
+			"revision": "a5b47d31c556af34a302ce5d659e6fea44d90de0",
+			"revisionTime": "2016-09-28T15:37:09Z"
+		}
+	],
+	"rootPath": "gitlab.hedenstroem.com/go/vaultenv"
+}
-- 
GitLab