forked from tellerops/teller
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhashicorp_vault.go
140 lines (116 loc) · 3.34 KB
/
hashicorp_vault.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package providers
import (
"fmt"
"sort"
"github.com/hashicorp/vault/api"
"github.com/spectralops/teller/pkg/core"
"github.com/spectralops/teller/pkg/logging"
)
type HashicorpClient interface {
Read(path string) (*api.Secret, error)
Write(path string, data map[string]interface{}) (*api.Secret, error)
}
type HashicorpVault struct {
client HashicorpClient
logger logging.Logger
}
func NewHashicorpVault(logger logging.Logger) (core.Provider, error) {
conf := api.DefaultConfig()
err := conf.ReadEnvironment()
if err != nil {
return nil, err
}
client, err := api.NewClient(conf)
if err != nil {
return nil, err
}
return &HashicorpVault{client: client.Logical(), logger: logger}, nil
}
func (h *HashicorpVault) Name() string {
return "hashicorp_vault"
}
func (h *HashicorpVault) GetMapping(p core.KeyPath) ([]core.EnvEntry, error) {
secret, err := h.getSecret(p)
if err != nil {
return nil, err
}
// vault returns a secret kv struct as either data{} or data.data{} depending on engine
var k map[string]interface{}
if val, ok := secret.Data["data"]; ok {
k = val.(map[string]interface{})
} else {
k = secret.Data
}
entries := []core.EnvEntry{}
for k, v := range k {
entries = append(entries, p.FoundWithKey(k, v.(string)))
}
sort.Sort(core.EntriesByKey(entries))
return entries, nil
}
func (h *HashicorpVault) Get(p core.KeyPath) (*core.EnvEntry, error) {
secret, err := h.getSecret(p)
if err != nil {
return nil, err
}
if secret == nil {
h.logger.WithField("path", p.Path).Debug("secret is empty")
ent := p.Missing()
return &ent, nil
}
// vault returns a secret kv struct as either data{} or data.data{} depending on engine
var data map[string]interface{}
if val, ok := secret.Data["data"]; ok {
data = val.(map[string]interface{})
} else {
data = secret.Data
}
k := data[p.Env]
if p.Field != "" {
h.logger.WithField("path", p.Path).Debug("`env` attribute not found in returned data. take `field` attribute")
k = data[p.Field]
}
if k == nil {
h.logger.WithField("path", p.Path).Debug("key not found")
ent := p.Missing()
return &ent, nil
}
ent := p.Found(k.(string))
return &ent, nil
}
func (h *HashicorpVault) Put(p core.KeyPath, val string) error {
k := p.Env
if p.Field != "" {
h.logger.WithField("path", p.Path).Debug("`env` attribute not configured. take `field` attribute")
k = p.Field
}
m := map[string]string{k: val}
h.logger.WithField("path", p.Path).Debug("write secret")
_, err := h.client.Write(p.Path, map[string]interface{}{"data": m})
return err
}
func (h *HashicorpVault) PutMapping(p core.KeyPath, m map[string]string) error {
h.logger.WithField("path", p.Path).Debug("write secret")
_, err := h.client.Write(p.Path, map[string]interface{}{"data": m})
return err
}
func (h *HashicorpVault) Delete(kp core.KeyPath) error {
return fmt.Errorf("%s does not implement delete yet", h.Name())
}
func (h *HashicorpVault) DeleteMapping(kp core.KeyPath) error {
return fmt.Errorf("%s does not implement delete yet", h.Name())
}
func (h *HashicorpVault) getSecret(kp core.KeyPath) (*api.Secret, error) {
h.logger.WithField("path", kp.Path).Debug("read secret")
secret, err := h.client.Read(kp.Path)
if err != nil {
return nil, err
}
if secret == nil || len(secret.Data) == 0 {
return nil, nil
}
if len(secret.Warnings) > 0 {
fmt.Println(secret.Warnings)
}
return secret, nil
}