smartconfig/resolver_vault.go
sneak 8a38afba5e passes tests, has cli filter now.
* still has not been *really* tested yet
2025-07-20 15:29:06 +02:00

55 lines
1.3 KiB
Go

package smartconfig
import (
"fmt"
"strings"
vaultapi "github.com/hashicorp/vault/api"
)
// VaultResolver retrieves secrets from HashiCorp Vault.
// Usage: ${VAULT:secret/data/myapp:password}
type VaultResolver struct{}
// Resolve retrieves the secret value from Vault.
func (r *VaultResolver) Resolve(value string) (string, error) {
config := vaultapi.DefaultConfig()
client, err := vaultapi.NewClient(config)
if err != nil {
return "", fmt.Errorf("failed to create Vault client: %w", err)
}
// Expect format: "path:key" e.g., "secret/data/myapp:password"
parts := strings.SplitN(value, ":", 2)
if len(parts) != 2 {
return "", fmt.Errorf("invalid Vault path format, expected PATH:KEY")
}
path := parts[0]
key := parts[1]
secret, err := client.Logical().Read(path)
if err != nil {
return "", fmt.Errorf("failed to read secret from Vault: %w", err)
}
if secret == nil || secret.Data == nil {
return "", fmt.Errorf("no secret found at path %s", path)
}
// Handle KV v2 format
data, ok := secret.Data["data"].(map[string]interface{})
if ok {
if val, ok := data[key].(string); ok {
return val, nil
}
}
// Handle KV v1 format
if val, ok := secret.Data[key].(string); ok {
return val, nil
}
return "", fmt.Errorf("key %s not found in secret", key)
}