-
Notifications
You must be signed in to change notification settings - Fork 9
/
vaultsecrets.go
110 lines (98 loc) · 3.53 KB
/
vaultsecrets.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package vaultsecrets
import (
"fmt"
"github.com/chrismellard/secretfacade/pkg/secretstore"
"github.com/hashicorp/vault/api"
"github.com/pkg/errors"
)
func NewVaultSecretManager(vaultToken string, caCertPath string) (secretstore.Interface, error) {
config := api.Config{}
err := config.ConfigureTLS(&api.TLSConfig{
CACert: caCertPath,
})
if err != nil {
return nil, errors.Wrap(err, "error configuring TLS ca cert for Hashicorp Vault API")
}
client, err := api.NewClient(nil)
if err != nil {
return nil, errors.Wrap(err, "error creating Hasicorp Vault API client")
}
client.SetToken(vaultToken)
return &vaultSecretManager{client}, nil
}
type vaultSecretManager struct {
vaultApi *api.Client
}
func (v vaultSecretManager) GetSecret(location string, secretName string, secretKey string) (string, error) {
secret, err := getSecret(v.vaultApi, location, secretName)
if err != nil || secret == nil {
return "", errors.Wrapf(err, "error getting secret %s from Hasicorp vault %s", secretName, location)
}
mapData, err := getSecretData(secret)
if err != nil {
return "", errors.Wrapf(err, "error converting secret data retrieved for secret %s from Hashicorp Vault %s", secretName, location)
}
secretString, err := getSecretKeyString(mapData, secretKey)
if err != nil {
return "", errors.Wrapf(err, "error converting string data for secret %s from Hashicorp Vault %s", secretName, location)
}
return secretString, nil
}
func (v vaultSecretManager) SetSecret(location string, secretName string, secretValue *secretstore.SecretValue) error {
secret, err := getSecret(v.vaultApi, location, secretName)
if err != nil {
return errors.Wrapf(err, "error getting secret %s in Hashicorp vault %s prior to setting", secretName, location)
}
newSecretData := map[string]interface{}{}
if secret != nil && !secretValue.Overwrite {
newSecretData, err = getSecretData(secret)
if err != nil {
return errors.Wrapf(err, "error retrieving secret data in payload for secret %s in Hashicorp Vault %s", secretName, location)
}
}
for k, v := range secretValue.PropertyValues {
newSecretData[k] = v
}
data := map[string]interface{}{
"data": newSecretData,
}
_, err = v.vaultApi.Logical().Write(secretName, data)
if err != nil {
return errors.Wrapf(err, "error writing secret %s to Hashicorp Vault %s", secretName, location)
}
return nil
}
func getSecret(client *api.Client, location string, secretName string) (*api.Secret, error) {
err := client.SetAddress(location)
if err != nil {
return nil, errors.Wrapf(err, "error setting location of Hashicorp vault %s on client", location)
}
logical := client.Logical()
secret, err := logical.Read(secretName)
if err != nil {
return nil, errors.Wrapf(err, "error reading secret %s from Hashicorp Vault API at %s", secretName, location)
}
return secret, nil
}
func getSecretData(secret *api.Secret) (map[string]interface{}, error) {
data, ok := secret.Data["data"]
if !ok {
return nil, fmt.Errorf("data payload does not exist in Hasicorp Vault secret")
}
mapData, ok := data.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("data is not of type map[string]interface{} in Hashicorp Vault secret")
}
return mapData, nil
}
func getSecretKeyString(secretData map[string]interface{}, secretKey string) (string, error) {
value, ok := secretData[secretKey]
if !ok {
return "", fmt.Errorf("%s does not occur in secret data", secretKey)
}
stringValue, ok := value.(string)
if !ok {
return "", fmt.Errorf("non string data type found in secret data for key %s", secretKey)
}
return stringValue, nil
}