90 lines
1.9 KiB
Go
90 lines
1.9 KiB
Go
package secret
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
vault "github.com/hashicorp/vault/api"
|
|
)
|
|
|
|
type vaultProvider struct{}
|
|
|
|
// Vault provider uses Hashicorp Vault for secrets storage.
|
|
//
|
|
// The secretKey is used to
|
|
func Vault() Provider {
|
|
return vaultProvider{}
|
|
}
|
|
|
|
func (p vaultProvider) GetSecret(key string) (value []byte, err error) {
|
|
var (
|
|
config = vault.DefaultConfig()
|
|
client *vault.Client
|
|
)
|
|
if client, err = vault.NewClient(config); err != nil {
|
|
return
|
|
}
|
|
|
|
var mounts map[string]*vault.MountOutput
|
|
if mounts, err = client.Sys().ListMounts(); err != nil {
|
|
return
|
|
}
|
|
|
|
var (
|
|
mount *vault.MountOutput
|
|
location string
|
|
)
|
|
if mount, location, err = p.split(key, mounts); err != nil {
|
|
return
|
|
}
|
|
|
|
switch mount.Type {
|
|
case "generic", "kv":
|
|
// Supported
|
|
default:
|
|
return nil, fmt.Errorf("secret: mount type %q is not supported", mount.Type)
|
|
}
|
|
|
|
var secret *vault.Secret
|
|
if secret, err = client.Logical().Read(location); err != nil {
|
|
return
|
|
} else if secret == nil || len(secret.Data) == 0 {
|
|
return nil, NotFound{Key: key}
|
|
}
|
|
|
|
data, ok := secret.Data["data"].(map[string]interface{})
|
|
if !ok {
|
|
return nil, NotFound{Key: key}
|
|
}
|
|
|
|
if len(data) == 1 {
|
|
for _, item := range data {
|
|
switch data := item.(type) {
|
|
case []byte:
|
|
return data, nil
|
|
case string:
|
|
return []byte(data), nil
|
|
default:
|
|
return nil, fmt.Errorf("secret: unexpected return type %T", data)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, AmbiguousKey{Key: key}
|
|
}
|
|
|
|
func (p vaultProvider) split(key string, mounts map[string]*vault.MountOutput) (mount *vault.MountOutput, location string, err error) {
|
|
location = strings.TrimPrefix(key, "/")
|
|
|
|
var tree string
|
|
for tree, mount = range mounts {
|
|
if strings.HasPrefix(location, tree) {
|
|
if mount.Type == "kv" && mount.Options["version"] == "2" {
|
|
location = tree + "data/" + location[len(tree):]
|
|
}
|
|
return
|
|
}
|
|
}
|
|
return nil, "", fmt.Errorf("secret: no Vault mount found for secret path %q", key)
|
|
}
|