@@ -11,8 +11,9 @@ import (
11
11
)
12
12
13
13
type Reader struct {
14
- client * vault.Client
15
- mounts Mounts
14
+ client * vault.Client
15
+ canDetectMounts bool
16
+ mounts Mounts
16
17
}
17
18
18
19
type EnvVars map [string ]string
@@ -65,21 +66,21 @@ func (s KVSecretBlock) GetOutput(ctx context.Context, r *Reader) (OutputList, er
65
66
}
66
67
}
67
68
68
- // The first thing we need to do is get the mount point for the KV engine
69
+ // Get the Mount Point for the Secret
69
70
mountPoint , secretPath := r .MountAndPath (s .Path )
70
71
if mountPoint == "" {
71
72
return nil , fmt .Errorf ("no mount point found for path %s" , s .Path )
72
73
}
73
74
74
- // V2 KV Secrets
75
- if r . mounts [mountPoint ].Type == "kv" && r .mounts [mountPoint ].Version == "2" {
75
+ // Assume v2 if we can detect mounts and it's a KV engine, or if it's explicitly v2
76
+ if ! r . canDetectMounts || ( r . mounts [mountPoint ].Type == "kv" && r .mounts [mountPoint ].Version == "2" ) {
76
77
// Get Secret
77
78
resp , err := r .client .Secrets .KvV2Read (ctx , secretPath , vault .WithMountPath (mountPoint ))
78
79
if err != nil {
79
80
if vault .IsErrorStatus (err , http .StatusNotFound ) {
80
- return nil , fmt .Errorf ("secret does not exist: '%s'" , s .Path )
81
+ return nil , fmt .Errorf ("kv2 secret does not exist: '%s'" , s .Path )
81
82
}
82
- return nil , fmt .Errorf ("error reading path '%s': %w" , s .Path , err )
83
+ return nil , fmt .Errorf ("error reading kv2 path '%s': %w" , s .Path , err )
83
84
}
84
85
// For testing purposes, we want to order this
85
86
envVars := []string {}
@@ -103,7 +104,7 @@ func (s KVSecretBlock) GetOutput(ctx context.Context, r *Reader) (OutputList, er
103
104
// Treat it as a KVv1 secret
104
105
resp , err := r .client .Secrets .KvV1Read (ctx , secretPath , vault .WithMountPath (mountPoint ))
105
106
if err != nil {
106
- return nil , fmt .Errorf ("error reading path %s: %w" , s .Path , err )
107
+ return nil , fmt .Errorf ("error reading kv1 path %s: %w" , s .Path , err )
107
108
}
108
109
for varName , varKey := range s .Vars {
109
110
if _ , hasValue := resp .Data [varKey ]; ! hasValue {
@@ -133,23 +134,83 @@ func (s KVSecrets) GetOutput(ctx context.Context, r *Reader) (OutputList, error)
133
134
return output , nil
134
135
}
135
136
137
+ // KV1Secrets is a list of Key-Value Version 1 Secrets
138
+ type KV1Secrets []KV1SecretBlock
139
+
140
+ type KV1SecretBlock struct {
141
+ Path string
142
+ Vars KVSecret
143
+ }
144
+
145
+ func (s KV1SecretBlock ) GetOutput (ctx context.Context , r * Reader ) (OutputList , error ) {
146
+ output := OutputList {}
147
+
148
+ // Initialize the Vault Client if Necessary
149
+ if r .client == nil {
150
+ err := r .InitVault ()
151
+ if err != nil {
152
+ return nil , err
153
+ }
154
+ }
155
+
156
+ // The first thing we need to do is get the mount point for the KV engine
157
+ mountPoint , secretPath := r .MountAndPath (s .Path )
158
+ if mountPoint == "" {
159
+ return nil , fmt .Errorf ("no mount point found for path %s" , s .Path )
160
+ }
161
+
162
+ // Treat it as a KVv1 secret
163
+ resp , err := r .client .Secrets .KvV1Read (ctx , secretPath , vault .WithMountPath (mountPoint ))
164
+ if err != nil {
165
+ return nil , fmt .Errorf ("error reading kv1 path %s: %w" , s .Path , err )
166
+ }
167
+ for varName , varKey := range s .Vars {
168
+ if _ , hasValue := resp .Data [varKey ]; ! hasValue {
169
+ return nil , fmt .Errorf ("key %s not found in path %s" , varKey , s .Path )
170
+ }
171
+ val := fmt .Sprintf ("%s" , resp .Data [varKey ])
172
+ output = append (output , Output {
173
+ Key : varName ,
174
+ Value : val ,
175
+ Comment : fmt .Sprintf ("Path: %s, Key: %s" , s .Path , varKey ),
176
+ })
177
+ }
178
+
179
+ return output , nil
180
+ }
181
+
182
+ func (s KV1Secrets ) GetOutput (ctx context.Context , r * Reader ) (OutputList , error ) {
183
+ output := OutputList {}
184
+ for _ , block := range s {
185
+ blockOutput , err := block .GetOutput (ctx , r )
186
+ if err != nil {
187
+ return nil , err
188
+ }
189
+ output = append (output , blockOutput ... )
190
+ }
191
+ return output , nil
192
+ }
193
+
136
194
type DC struct {
137
- Vars EnvVars `yaml:"vars,omitempty"`
138
- Secrets Secrets `yaml:"secrets,omitempty"`
139
- KVSecrets KVSecrets `yaml:"kv_secrets,omitempty"`
195
+ Vars EnvVars `yaml:"vars,omitempty"`
196
+ Secrets Secrets `yaml:"secrets,omitempty"`
197
+ KVSecrets KVSecrets `yaml:"kv_secrets,omitempty"`
198
+ KV1Secrets KVSecrets `yaml:"kv1_secrets,omitempty"`
140
199
}
141
200
142
201
type Environment struct {
143
- Vars EnvVars `yaml:"vars,omitempty"`
144
- Secrets Secrets `yaml:"secrets,omitempty"`
145
- KVSecrets KVSecrets `yaml:"kv_secrets,omitempty"`
146
- Dcs map [string ]DC `yaml:"dcs,omitempty"`
202
+ Vars EnvVars `yaml:"vars,omitempty"`
203
+ Secrets Secrets `yaml:"secrets,omitempty"`
204
+ KVSecrets KVSecrets `yaml:"kv_secrets,omitempty"`
205
+ KV1Secrets KVSecrets `yaml:"kv1_secrets,omitempty"`
206
+ Dcs map [string ]DC `yaml:"dcs,omitempty"`
147
207
}
148
208
149
209
type Variables struct {
150
210
Vars EnvVars `yaml:"vars,omitempty"`
151
211
Secrets Secrets `yaml:"secrets,omitempty"`
152
212
KVSecrets KVSecrets `yaml:"kv_secrets,omitempty"`
213
+ KV1Secrets KVSecrets `yaml:"kv1_secrets,omitempty"`
153
214
Environments map [string ]Environment `yaml:"environments,omitempty"`
154
215
}
155
216
@@ -192,29 +253,30 @@ func (r *Reader) InitVault() error {
192
253
return err
193
254
}
194
255
r .client = vaultClient
256
+ r .canDetectMounts = false
195
257
196
258
// Get mount info
197
259
resp , err := vaultClient .System .MountsListSecretsEngines (context .Background ())
198
- if err != nil {
199
- return fmt .Errorf ("failure reading secret mounts: %w" , err )
200
- }
201
-
202
- mounts := Mounts {}
203
- for mount , details := range resp .Data {
204
- detailMap := details .(map [string ]interface {})
205
- thisMount := MountInfo {
206
- Type : detailMap ["type" ].(string ),
207
- }
208
- if options , hasOptions := detailMap ["options" ]; hasOptions && options != nil {
209
- optionMap := options .(map [string ]interface {})
210
- if version , hasVersion := optionMap ["version" ]; hasVersion {
211
- thisMount .Version = version .(string )
260
+ if err == nil {
261
+ r .canDetectMounts = true
262
+ mounts := Mounts {}
263
+ for mount , details := range resp .Data {
264
+ detailMap := details .(map [string ]interface {})
265
+ thisMount := MountInfo {
266
+ Type : detailMap ["type" ].(string ),
212
267
}
268
+ if options , hasOptions := detailMap ["options" ]; hasOptions && options != nil {
269
+ optionMap := options .(map [string ]interface {})
270
+ if version , hasVersion := optionMap ["version" ]; hasVersion {
271
+ thisMount .Version = version .(string )
272
+ }
273
+ }
274
+ mounts [mount ] = thisMount
213
275
}
214
- mounts [mount ] = thisMount
276
+
277
+ r .mounts = mounts
215
278
}
216
279
217
- r .mounts = mounts
218
280
return nil
219
281
}
220
282
@@ -223,10 +285,16 @@ func NewReader() (*Reader, error) {
223
285
}
224
286
225
287
func (r * Reader ) MountAndPath (path string ) (string , string ) {
226
- for mount := range r .mounts {
227
- if strings .HasPrefix (path , mount ) {
228
- return mount , strings .TrimPrefix (path , mount )
288
+ if r .canDetectMounts {
289
+ for mount := range r .mounts {
290
+ if strings .HasPrefix (path , mount ) {
291
+ return mount , strings .TrimPrefix (path , mount )
292
+ }
229
293
}
294
+ } else {
295
+ // Take the first part of the path
296
+ parts := strings .SplitN (path , "/" , 2 )
297
+ return parts [0 ], parts [1 ]
230
298
}
231
299
return "" , ""
232
300
}
@@ -246,6 +314,11 @@ func (r *Reader) Read(ctx context.Context, input *Variables, env string, dc stri
246
314
return nil , fmt .Errorf ("kv secret error: %w" , err )
247
315
}
248
316
output = append (output , kvOut ... )
317
+ kv1Out , err := input .KV1Secrets .GetOutput (ctx , r )
318
+ if err != nil {
319
+ return nil , fmt .Errorf ("kv1 secret error: %w" , err )
320
+ }
321
+ output = append (output , kv1Out ... )
249
322
secretOut , err := input .Secrets .GetOutput (ctx , r )
250
323
if err != nil {
251
324
return nil , fmt .Errorf ("secret error: %w" , err )
@@ -258,11 +331,19 @@ func (r *Reader) Read(ctx context.Context, input *Variables, env string, dc stri
258
331
Comment : fmt .Sprintf ("Environment: %s" , env ),
259
332
})
260
333
output = append (output , input .Environments [env ].Vars .GetOutput ()... )
334
+ // KV (autodetect or v2)
261
335
kvOut , err := input .Environments [env ].KVSecrets .GetOutput (ctx , r )
262
336
if err != nil {
263
337
return nil , fmt .Errorf ("kv secret error: %w" , err )
264
338
}
265
339
output = append (output , kvOut ... )
340
+ // KV1
341
+ kv1Out , err := input .Environments [env ].KV1Secrets .GetOutput (ctx , r )
342
+ if err != nil {
343
+ return nil , fmt .Errorf ("kv1 secret error: %w" , err )
344
+ }
345
+ output = append (output , kv1Out ... )
346
+ // Secrets
266
347
secretOut , err := input .Environments [env ].Secrets .GetOutput (ctx , r )
267
348
if err != nil {
268
349
return nil , fmt .Errorf ("secret error: %w" , err )
@@ -276,11 +357,19 @@ func (r *Reader) Read(ctx context.Context, input *Variables, env string, dc stri
276
357
Comment : fmt .Sprintf ("Datacenter: %s" , dc ),
277
358
})
278
359
output = append (output , input .Environments [env ].Dcs [dc ].Vars .GetOutput ()... )
360
+ // KV (autodetect or v2)
279
361
kvOut , err := input .Environments [env ].Dcs [dc ].KVSecrets .GetOutput (ctx , r )
280
362
if err != nil {
281
363
return nil , fmt .Errorf ("kv secret error: %w" , err )
282
364
}
283
365
output = append (output , kvOut ... )
366
+ // KV1
367
+ kv1Out , err := input .Environments [env ].Dcs [dc ].KV1Secrets .GetOutput (ctx , r )
368
+ if err != nil {
369
+ return nil , fmt .Errorf ("kv1 secret error: %w" , err )
370
+ }
371
+ output = append (output , kv1Out ... )
372
+ // Secrets
284
373
secretOut , err := input .Environments [env ].Dcs [dc ].Secrets .GetOutput (ctx , r )
285
374
if err != nil {
286
375
return nil , fmt .Errorf ("secret error: %w" , err )
0 commit comments