vault

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 26, 2025 License: Apache-2.0 Imports: 7 Imported by: 0

README

Vault Resolver

The fuda/vault package provides a HashiCorp Vault resolver for fetching secrets directly into your configuration struct.

Installation

The Vault package is a separate Go module to avoid adding the Vault SDK as a core fuda dependency. Install it with:

go get github.com/arloliu/fuda/vault

Then import:

import "github.com/arloliu/fuda/vault"

Quick Start

package main

import (
    "log"
    "os"

    "github.com/arloliu/fuda"
    "github.com/arloliu/fuda/vault"
)

type Config struct {
    DBPassword string `ref:"vault:///secret/data/myapp#db_password"`
    APIKey     string `ref:"vault:///secret/data/myapp#api_key"`
}

func main() {
    // Create Vault resolver
    resolver, err := vault.NewResolver(
        vault.WithAddress("https://vault.example.com:8200"),
        vault.WithToken(os.Getenv("VAULT_TOKEN")),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Use with fuda
    loader, err := fuda.New().
        FromFile("config.yaml").
        WithRefResolver(resolver).
        Build()
    if err != nil {
        log.Fatal(err)
    }

    var cfg Config
    if err := loader.Load(&cfg); err != nil {
        log.Fatal(err)
    }
}

URI Format

vault:///<mount>/<path>#<field>
Component Description
mount Secrets engine mount path (e.g., secret)
path Path to the secret
field Field name within the secret
Examples
// KV v2 (versioned secrets)
DBPassword string `ref:"vault:///secret/data/myapp#password"`

// KV v1 (unversioned)
APIKey string `ref:"vault:///kv/myapp#api_key"`

// Database dynamic secrets
DBUser string `ref:"vault:///database/creds/readonly#username"`

// Dynamic path from config
SecretPath string `yaml:"secret_path"`
Token      string `refFrom:"SecretPath"`  // Supports vault:// URIs

Authentication Methods

Token Authentication

Simplest method, suitable for development or CI/CD:

vault.WithToken(os.Getenv("VAULT_TOKEN"))
Kubernetes Authentication

Recommended for pods running in Kubernetes:

vault.WithKubernetesAuth(
    "my-app-role",
    "/var/run/secrets/kubernetes.io/serviceaccount/token",
)

For custom auth mount paths:

vault.WithKubernetesAuthMount(
    "custom-k8s",  // Mount path
    "my-role",
    "/var/run/secrets/kubernetes.io/serviceaccount/token",
)
AppRole Authentication

Machine-to-machine authentication:

vault.WithAppRole(
    os.Getenv("VAULT_ROLE_ID"),
    os.Getenv("VAULT_SECRET_ID"),
)

Additional Options

// Vault Enterprise namespace
vault.WithNamespace("my-team")

// Custom TLS configuration
vault.WithTLSConfig(&api.TLSConfig{
    CACert:   "/path/to/ca.crt",
    Insecure: false,
})

Kubernetes Deployment Example

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      serviceAccountName: my-app
      containers:
        - name: app
          image: my-app:latest
          volumeMounts:
            - name: config
              mountPath: /etc/config
      volumes:
        - name: config
          configMap:
            name: my-app-config

Create a Vault role for the service account:

vault write auth/kubernetes/role/my-app-role \
    bound_service_account_names=my-app \
    bound_service_account_namespaces=default \
    policies=my-app-policy \
    ttl=1h

Thread Safety

The Resolver is safe for concurrent use after creation. Multiple goroutines can call Resolve() simultaneously.

Error Handling

_, err := resolver.Resolve(ctx, "vault:///secret/data/missing#field")
if err != nil {
    // Common errors:
    // - "vault secret not found at ..."
    // - "field not found in vault secret at ..."
    // - "vault authentication failed: ..."
}

Documentation

Overview

Package vault provides a HashiCorp Vault resolver for fuda.

This package implements [fuda.RefResolver] to fetch secrets from Vault using the vault:// URI scheme. It supports multiple authentication methods including Token, Kubernetes, and AppRole.

Basic usage:

resolver, err := vault.NewResolver(
    vault.WithAddress("https://vault.example.com:8200"),
    vault.WithToken(os.Getenv("VAULT_TOKEN")),
)
if err != nil {
    log.Fatal(err)
}

loader, _ := fuda.New().
    FromFile("config.yaml").
    WithRefResolver(resolver).
    Build()

URI Format

The vault resolver uses the following URI format:

vault:///<mount>/<path>#<field>

Examples:

  • vault:///secret/data/myapp#password (KV v2)
  • vault:///kv/myapp#api_key (KV v1)
  • vault:///database/creds/readonly#username (Dynamic secrets)

Authentication Methods

Token authentication:

vault.WithToken(os.Getenv("VAULT_TOKEN"))

Kubernetes authentication (for pods running in K8s):

vault.WithKubernetesAuth("my-role", "/var/run/secrets/kubernetes.io/serviceaccount/token")

AppRole authentication:

vault.WithAppRole(roleID, secretID)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option func(*resolverConfig)

Option configures a Vault resolver.

func WithAddress

func WithAddress(addr string) Option

WithAddress sets the Vault server address. This is required for creating a resolver.

Example:

vault.WithAddress("https://vault.example.com:8200")

func WithAppRole

func WithAppRole(roleID, secretID string) Option

WithAppRole configures AppRole authentication. AppRole is designed for machine-to-machine authentication.

Parameters:

  • roleID: The AppRole role ID
  • secretID: The AppRole secret ID

Example:

vault.WithAppRole(os.Getenv("VAULT_ROLE_ID"), os.Getenv("VAULT_SECRET_ID"))

func WithAppRoleMount

func WithAppRoleMount(mount, roleID, secretID string) Option

WithAppRoleMount configures AppRole authentication with a custom mount path. Use this if your AppRole auth method is mounted at a non-default path.

Example:

vault.WithAppRoleMount("my-approle", roleID, secretID)

func WithKubernetesAuth

func WithKubernetesAuth(role, jwtPath string) Option

WithKubernetesAuth configures Kubernetes authentication. This is the recommended method for applications running in Kubernetes.

Parameters:

  • role: The Vault role to authenticate as
  • jwtPath: Path to the service account token (typically /var/run/secrets/kubernetes.io/serviceaccount/token)

Example:

vault.WithKubernetesAuth("my-app-role", "/var/run/secrets/kubernetes.io/serviceaccount/token")

func WithKubernetesAuthMount

func WithKubernetesAuthMount(mount, role, jwtPath string) Option

WithKubernetesAuthMount configures Kubernetes authentication with a custom mount path. Use this if your Kubernetes auth method is mounted at a non-default path.

Example:

vault.WithKubernetesAuthMount("my-k8s", "my-app-role", "/var/run/secrets/kubernetes.io/serviceaccount/token")

func WithNamespace

func WithNamespace(ns string) Option

WithNamespace sets the Vault namespace (Enterprise feature). Namespaces provide tenant isolation in Vault Enterprise.

Example:

vault.WithNamespace("my-team")

func WithTLSConfig

func WithTLSConfig(cfg *vaultapi.TLSConfig) Option

WithTLSConfig sets custom TLS configuration for the Vault client.

Example:

vault.WithTLSConfig(&api.TLSConfig{
    CACert: "/path/to/ca.crt",
    Insecure: false,
})

func WithToken

func WithToken(token string) Option

WithToken sets a static token for authentication. This is the simplest authentication method, suitable for development or when tokens are injected via environment variables.

Example:

vault.WithToken(os.Getenv("VAULT_TOKEN"))

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver implements fuda.RefResolver for HashiCorp Vault. It resolves vault:// URIs by fetching secrets from a Vault server.

func NewResolver

func NewResolver(opts ...Option) (*Resolver, error)

NewResolver creates a new Vault resolver with the given options.

At minimum, you must provide an address and an authentication method:

resolver, err := vault.NewResolver(
    vault.WithAddress("https://vault.example.com:8200"),
    vault.WithToken(os.Getenv("VAULT_TOKEN")),
)

Available options:

func (*Resolver) Client

func (r *Resolver) Client() *vaultapi.Client

Client returns the underlying Vault API client for advanced usage. This allows users to perform operations not covered by the resolver interface.

func (*Resolver) Resolve

func (r *Resolver) Resolve(ctx context.Context, uri string) ([]byte, error)

Resolve fetches the secret value from Vault for the given URI.

URI format: vault:///<mount>/<path>#<field>

The resolver automatically handles both KV v1 and KV v2 secrets engines. For KV v2, the data is extracted from the nested "data" field.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL