diff --git a/pkg/vault-handler/vault.go b/pkg/vault-handler/vault.go index 8b82dfa..97b66e2 100644 --- a/pkg/vault-handler/vault.go +++ b/pkg/vault-handler/vault.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "log" + "strings" vaultapi "github.com/hashicorp/vault/api" ) @@ -40,9 +41,6 @@ func (v *Vault) Read(path, key string) ([]byte, error) { var err error log.Printf("[Vault] Reading data from path '%s', looking for key '%s'", path, key) - headers := map[string][]string{"X-Vault-Token": []string{v.token}} - v.client.SetHeaders(headers) - v.client.SetToken(v.token) if secret, err = v.client.Logical().Read(path); err != nil { return nil, err @@ -54,6 +52,31 @@ func (v *Vault) Read(path, key string) ([]byte, error) { return v.extractKey(secret.Data, key) } +// Write data to a vault path. Wrapper around Logical Write function in Vault API. +func (v *Vault) Write(path string, data map[string]interface{}) error { + var err error + + log.Printf("[Vault] Writting data on path '%s'", path) + + // wrapping up data for kv-v2 + if strings.HasPrefix(path, "secret/data") { + log.Print("[Vault] Using V2 API style, adding 'data' as key.") + data = map[string]interface{}{"data": data} + } + if _, err = v.client.Logical().Write(path, data); err != nil { + return err + } + + return nil +} + +// setHeaders prepare http request headers to inform token. +func (v *Vault) setHeaders() { + headers := map[string][]string{"X-Vault-Token": []string{v.token}} + v.client.SetHeaders(headers) + v.client.SetToken(v.token) +} + // AppRoleAuth execute approle authentication. func (v *Vault) AppRoleAuth(roleID, secretID string) error { var secret *vaultapi.Secret @@ -71,6 +94,7 @@ func (v *Vault) AppRoleAuth(roleID, secretID string) error { log.Printf("[Vault] Obtained a token via AppRole.") // saving token for next API calls. v.token = secret.Auth.ClientToken + v.setHeaders() return nil } @@ -78,6 +102,7 @@ func (v *Vault) AppRoleAuth(roleID, secretID string) error { // TokenAuth execute token based authentication. func (v *Vault) TokenAuth(token string) { v.token = token + v.setHeaders() } // NewVault creates a Vault instance, by bootstrapping it's API client. diff --git a/pkg/vault-handler/vault_test.go b/pkg/vault-handler/vault_test.go index 18efbe7..f533cef 100644 --- a/pkg/vault-handler/vault_test.go +++ b/pkg/vault-handler/vault_test.go @@ -1,13 +1,16 @@ package vaulthandler import ( - "log" "os" "testing" "github.com/stretchr/testify/assert" ) +const ( + foo = "bar" +) + var vault *Vault func TestVaultNewVault(t *testing.T) { @@ -23,15 +26,25 @@ func TestVaultAppRoleAuth(t *testing.T) { roleID := os.Getenv("VAULT_HANDLER_VAULT_ROLE_ID") secretID := os.Getenv("VAULT_HANDLER_VAULT_SECRET_ID") - log.Printf("Role-ID: '%s', Secret-ID: '%s'", roleID, secretID) + t.Logf("Role-ID: '%s', Secret-ID: '%s'", roleID, secretID) + if roleID == "" || secretID == "" { + t.Fatalf("Can't find role-id ('%s'), secret-id ('%s') in the environment", roleID, secretID) + } + err := vault.AppRoleAuth(roleID, secretID) assert.Nil(t, err) } +func TestVaultWrite(t *testing.T) { + err := vault.Write("secret/data/foo/bar/baz", map[string]interface{}{"foo": foo}) + + assert.Nil(t, err) +} + func TestVaultRead(t *testing.T) { out, err := vault.Read("secret/data/foo/bar/baz", "foo") assert.Nil(t, err) - log.Printf("out: '%#v'", out) + assert.Equal(t, string(out), foo) }