Skip to content

Commit

Permalink
Add methods to return the entire secret not only the value for one fi…
Browse files Browse the repository at this point in the history
…eld (#6)

* Add methods to return the entire secret not only the value for one field
  • Loading branch information
tbeaugrand authored Apr 7, 2021
1 parent 78c8883 commit 0693953
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 19 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Read secret (kv v1), returns the secret value
client.ReadSecret("path", "field")
```

Get secret (kv v1), returns the secret (map[string]interface{})
```
client.GetSecret("path")
```

List secret paths (kv v1), returns absolute secret path from base path.
```
client.ListSecretPath("basepath")
Expand All @@ -38,6 +43,11 @@ Read secret (kv v2), returns the secret value
client.ReadSecretKvV2("path", "field")
```

Get secret (kv v2), returns the secret (map[string]interface{})
```
client.GetSecretKvV2("path")
```

List secret paths (kv v2), returns absolute secret path from base path.
```
client.ListSecretPathKvV2("basepath")
Expand Down
55 changes: 37 additions & 18 deletions vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,54 +78,73 @@ func (vc *VaultClient) ListSecretPath(path string) ([]string, error) {
}

func (vc *VaultClient) ReadSecret(path string, field string) (string, error) {
secret, err := vc.client.Read(path)
secret, err := vc.GetSecret(path)
if err != nil {
return "", errors.Wrapf(err, "failed to read secret %q", path)
}
if secret == nil {
return "", errors.Errorf("no exist secret %q", path)
return "", errors.Wrapf(err, "failed to read secret in %q", path)
}

value, found := secret.Data[field]
value, found := secret[field]
if !found {
return "", errors.Errorf("no field %q for secret %q", field, secret.WrapInfo.CreationPath)
return "", errors.Errorf("no field %q for secret in %q", field, path)
}

convertedValue, ok := value.(string)
if !ok {
return "", errors.Errorf("secret %q in %q has type %T = %v", field, secret.WrapInfo.CreationPath, value, value)
return "", errors.Errorf("secret %q in %q has type %T = %v", field, path, value, value)
}
if convertedValue == "" {
return "", errors.Errorf("value is empty for field %q in %q", field, secret.WrapInfo.CreationPath)
return "", errors.Errorf("value is empty for field %q in %q", field, path)
}

return convertedValue, nil
}

func (vc *VaultClient) ReadSecretKvV2(path string, field string) (string, error) {
v2Path := kvV2Path(path, "data")
secret, err := vc.client.Read(v2Path)
func (vc *VaultClient) GetSecret(path string) (map[string]interface{}, error) {
secret, err := vc.client.Read(path)
if err != nil {
return "", errors.Wrapf(err, "failed to read secret %q", path)
return nil, errors.Wrapf(err, "failed to read secret in %q", path)
}

if secret == nil {
return "", errors.Errorf("No secret exist for this path %q", path)
return nil, errors.Errorf("no existing secret in %q", path)
}

m, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return "", errors.Errorf("Incompatible type %q key does not exist, %T %#v", "data", secret.Data["data"], secret.Data["data"])
return secret.Data, nil
}

func (vc *VaultClient) ReadSecretKvV2(path string, field string) (string, error) {
secret, err := vc.GetSecretKvV2(path)
if err != nil {
return "", errors.Wrapf(err, "failed to read secret in %q", path)
}

convertedValue, ok := m[field].(string)
convertedValue, ok := secret[field].(string)
if !ok {
return "", errors.Errorf("field %q does not exist for this secret %q", field, path)
}

return convertedValue, nil
}

func (vc *VaultClient) GetSecretKvV2(path string) (map[string]interface{}, error) {
v2Path := kvV2Path(path, "data")
secret, err := vc.client.Read(v2Path)
if err != nil {
return nil, errors.Wrapf(err, "failed to read secret in %q", path)
}

if secret == nil {
return nil, errors.Errorf("No secret exists in %q", path)
}

m, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return nil, errors.Errorf("Incompatible type %q key does not exist, %T %#v", "data", secret.Data["data"], secret.Data["data"])
}

return m, nil
}

func (vc *VaultClient) ListSecretPathKvV2(path string) ([]string, error) {
v2Path := kvV2Path(path, "metadata")

Expand Down
46 changes: 45 additions & 1 deletion vault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ func createTestVault(t *testing.T) (string, string) {

// Setup required secrets, policies, etc.
_, err = client.Logical().Write("secret/foo", map[string]interface{}{
"secret": "bar",
"secret": "bar",
"secret2": "bar2",
"secret3": "bar3",
})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -250,3 +252,45 @@ func TestListSecretV2(t *testing.T) {
_, err = client.ListSecretPathKvV2("secret/not_exist")
require.Error(t, err, "The path \"secret/not_exist\" does not exist")
}

func TestGetSecret(t *testing.T) {
addr, token := createTestVault(t)

os.Clearenv()
os.Setenv("VAULT_ADDR", addr)
os.Setenv("VAULT_TOKEN", token)

client, err := CreateClient()
require.NoError(t, err)

s, err := client.GetSecret("secret/foo")
require.NoError(t, err)

require.Equal(t, "bar", s["secret"])
require.Equal(t, "bar2", s["secret2"])
require.Equal(t, "bar3", s["secret3"])
}

func TestGetSecretKvV2(t *testing.T) {
os.Clearenv()
os.Setenv("VAULT_ADDR", v2Endpoint)
os.Setenv("VAULT_TOKEN", "root")

client, err := CreateClient()
require.NoError(t, err, "This should not fail")

addSecret(t, client, "secret/data/foo", map[string]interface{}{
"data": map[string]interface{}{
"secret": "bar",
"secret2": "bar2",
"secret3": "bar3",
},
})

s, err := client.GetSecretKvV2("secret/foo")
require.NoError(t, err)

require.Equal(t, "bar", s["secret"])
require.Equal(t, "bar2", s["secret2"])
require.Equal(t, "bar3", s["secret3"])
}

0 comments on commit 0693953

Please sign in to comment.