vault

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2025 License: Apache-2.0 Imports: 22 Imported by: 0

README

Vault

GitHub release Go Reference

A flexible Go library for secure secret management with multiple backend providers. Made for flow but can be used independently.

Features

  • Multiple Provider Support: Choose from local encrypted storage, system keyring, or external CLI tools
  • Pluggable Architecture: Easy to extend with custom providers
  • Type Safety: Strong typing for secrets with secure memory handling
  • Thread Safe: Concurrent access protection with read/write mutexes
  • Comprehensive API: Full CRUD operations plus metadata and existence checks

Quick Start

package main

import (
    "fmt"
    "github.com/flowexec/vault"
)

func main() {
    // Create a new AES vault
    v, err := vault.New("my-vault",
        vault.WithProvider(vault.ProviderTypeAES256),
        vault.WithLocalPath("/path/to/vault/storage"),
        vault.WithAESKeyFromEnv("VAULT_KEY"),
    )
    if err != nil {
        panic(err)
    }
    defer v.Close()

    // Store a secret
    secret := vault.NewSecretValue([]byte("my-secret-value"))
    err = v.SetSecret("api-key", secret)
    if err != nil {
        panic(err)
    }

    // Retrieve a secret
    retrieved, err := v.GetSecret("api-key")
    if err != nil {
        panic(err)
    }
    fmt.Println("Secret:", retrieved.PlainTextString())
}

Provider Types

Local Encrypted Providers
AES256 Provider

Stores secrets in an AES-256 encrypted file with configurable key sources.

provider, _, err := vault.New("my-vault",
    vault.WithProvider(vault.ProviderTypeAES256),
    vault.WithAESPath("~/secrets.vault"),
)

Key Generation:

key, err := vault.GenerateEncryptionKey()
// Store this key securely (environment variable, HSM, etc.)
Age Provider

Uses the age encryption tool with public key cryptography.

provider, _, err := vault.New("my-vault", 
    vault.WithProvider(vault.ProviderTypeAge),
    vault.WithAgePath("~/secrets.age"),
)

Key Generation:

age-keygen -o ~/.age/identity.txt
# Add recipients to vault configuration
Keyring Provider

Integrates with the operating system's secure keyring.

provider, _, err := vault.New("my-vault",
    vault.WithProvider(vault.ProviderTypeKeyring),
    vault.WithKeyringService("my-app-secrets"),
)

No additional setup required - uses OS authentication.

Unencrypted Provider

Stores secrets in plain text JSON files.

provider, _, err := vault.New("my-vault",
    vault.WithProvider(vault.ProviderTypeUnencrypted), 
    vault.WithUnencryptedPath("~/dev-secrets.json"),
)
External CLI Providers
External Provider

Integrates with any CLI tool for secret management. Supports popular tools like Bitwarden, 1Password, HashiCorp Vault, AWS SSM, and more.

config := &vault.Config{
    ID: "bitwarden",
    Type: vault.ProviderTypeExternal,
    External: &vault.ExternalConfig{
        Get: vault.CommandConfig{
            CommandTemplate: "bw get password {{key}}",
        },
        Set: vault.CommandConfig{
            CommandTemplate: "bw create item --name {{key}} --password {{value}}",
        },
        // ... other operations
    },
}

provider, err := vault.NewExternalVaultProvider(config)

External Provider Examples

Ready-to-use configurations for popular CLI tools are available in the examples/ directory:

See the examples README for detailed setup instructions.

Usage

Basic Operations
// Store a secret
secret := vault.NewSecretValue([]byte("my-secret-value"))
err = provider.SetSecret("api-key", secret)

// Retrieve the secret
retrieved, err := provider.GetSecret("api-key")
fmt.Println("Secret:", retrieved.PlainTextString())

// List all secrets
secrets, _ := provider.ListSecrets()

// Check if secret exists
exists, _ := provider.HasSecret("api-key")

// Get vault metadata
metadata := provider.Metadata()
Configuration from File
// Load configuration from JSON
config, err := vault.LoadConfigJSON("vault-config.json") 
provider, _, err := vault.New(config.ID, vault.WithProvider(config.Type))

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrSecretNotFound   = errors.New("secret not found")
	ErrInvalidKey       = errors.New("invalid secret key")
	ErrNoAccess         = errors.New("access denied")
	ErrInvalidConfig    = errors.New("invalid configuration")
	ErrVaultNotFound    = errors.New("vault not found")
	ErrDecryptionFailed = errors.New("decryption failed")
	ErrInvalidRecipient = errors.New("invalid recipient")
	ErrPathNotSecure    = errors.New("path is not secure")
)
View Source
var (
	DefaultVaultKeyEnv = "VAULT_KEY"
)

Functions

func DeriveEncryptionKey

func DeriveEncryptionKey(passphrase, sal string) (string, string, error)

DeriveEncryptionKey derives an AES encryption key from a passphrase

func GenerateEncryptionKey

func GenerateEncryptionKey() (string, error)

GenerateEncryptionKey generates a new AES encryption key

func New

func New(id string, opts ...Option) (Provider, *Config, error)

New creates a new vault instance with the provided ID and options

func SaveConfigJSON

func SaveConfigJSON(config Config, path string) error

SaveConfigJSON saves the vault configuration to a file in JSON format

func ValidateEncryptionKey

func ValidateEncryptionKey(key string) error

ValidateEncryptionKey checks if a key is valid by attempting to encrypt/decrypt test data

func ValidateSecretKey

func ValidateSecretKey(reference string) error

Types

type AES256Vault

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

AES256Vault manages operations on an instance of a local vault backed by AES256 symmetric encryption.

func NewAES256Vault

func NewAES256Vault(cfg *Config) (*AES256Vault, error)

func (*AES256Vault) Close

func (v *AES256Vault) Close() error

func (*AES256Vault) DeleteSecret

func (v *AES256Vault) DeleteSecret(key string) error

func (*AES256Vault) GetSecret

func (v *AES256Vault) GetSecret(key string) (Secret, error)

func (*AES256Vault) HasSecret

func (v *AES256Vault) HasSecret(key string) (bool, error)

func (*AES256Vault) ID

func (v *AES256Vault) ID() string

func (*AES256Vault) ListSecrets

func (v *AES256Vault) ListSecrets() ([]string, error)

func (*AES256Vault) Metadata

func (v *AES256Vault) Metadata() Metadata

func (*AES256Vault) SetSecret

func (v *AES256Vault) SetSecret(key string, secret Secret) error

type AESState

type AESState struct {
	Metadata `yaml:"metadata"`

	Version int               `json:"version"`
	ID      string            `yaml:"id"`
	Secrets map[string]string `yaml:"secrets"`
}

AESState represents the state of the local AES256 vault.

type AesConfig

type AesConfig struct {
	// Storage location for the vault file
	StoragePath string `json:"storage_path"`
	// DEK sources for decryption (in order of preference)
	KeySource []KeySource `json:"key_sources,omitempty"`
}

AesConfig contains local (AES256-based) vault configuration

func (*AesConfig) Validate

func (c *AesConfig) Validate() error

type AgeConfig

type AgeConfig struct {
	// Storage location for the vault file
	StoragePath string `json:"storage_path"`

	// Identity sources for decryption (in order of preference)
	IdentitySources []IdentitySource `json:"identity_sources,omitempty"`

	// Recipients who can decrypt secrets
	Recipients []string `json:"recipients,omitempty"`
}

AgeConfig contains local (age-based) vault configuration

func (*AgeConfig) Validate

func (c *AgeConfig) Validate() error

type AgeState

type AgeState struct {
	Metadata `json:"metadata"`

	Version    int               `json:"version"`
	ID         string            `json:"id"`
	Recipients []string          `json:"recipients"`
	Secrets    map[string]string `json:"secrets"`
}

AgeState represents the state of the local age vault

type AgeVault

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

AgeVault manages operations on an instance of a local vault backed by age encryption.

func NewAgeVault

func NewAgeVault(cfg *Config) (*AgeVault, error)

func (*AgeVault) AddRecipient

func (v *AgeVault) AddRecipient(publicKey string) error

func (*AgeVault) Close

func (v *AgeVault) Close() error

func (*AgeVault) DeleteSecret

func (v *AgeVault) DeleteSecret(key string) error

func (*AgeVault) GetSecret

func (v *AgeVault) GetSecret(key string) (Secret, error)

func (*AgeVault) HasSecret

func (v *AgeVault) HasSecret(key string) (bool, error)

func (*AgeVault) ID

func (v *AgeVault) ID() string

func (*AgeVault) ListRecipients

func (v *AgeVault) ListRecipients() ([]string, error)

func (*AgeVault) ListSecrets

func (v *AgeVault) ListSecrets() ([]string, error)

func (*AgeVault) Metadata

func (v *AgeVault) Metadata() Metadata

func (*AgeVault) RemoveRecipient

func (v *AgeVault) RemoveRecipient(publicKey string) error

func (*AgeVault) SetSecret

func (v *AgeVault) SetSecret(key string, value Secret) error

type CommandConfig added in v0.2.0

type CommandConfig struct {
	// CommandTemplate for building command arguments
	CommandTemplate string `json:"cmd"`
	// OutputTemplate for parsing command output
	OutputTemplate string `json:"output,omitempty"`
	// InputTemplate for providing input to the command
	InputTemplate string `json:"input,omitempty"`
}

CommandConfig represents a command template to be executed with its arguments

type Config

type Config struct {
	ID          string             `json:"id"`
	Type        ProviderType       `json:"type"`
	Age         *AgeConfig         `json:"age,omitempty"`
	Aes         *AesConfig         `json:"aes,omitempty"`
	External    *ExternalConfig    `json:"external,omitempty"`
	Keyring     *KeyringConfig     `json:"keyring,omitempty"`
	Unencrypted *UnencryptedConfig `json:"unencrypted,omitempty"`
}

func LoadConfigJSON

func LoadConfigJSON(path string) (Config, error)

LoadConfigJSON loads the vault configuration from a file in JSON format

func (*Config) Validate

func (c *Config) Validate() error

type ExternalConfig

type ExternalConfig struct {
	// Get CommandConfig for the get operation
	Get CommandConfig `json:"get,omitempty"`
	// Set CommandConfig for the set operation
	Set CommandConfig `json:"set,omitempty"`
	// Delete CommandConfig for the delete operation
	Delete CommandConfig `json:"delete,omitempty"`
	// List CommandConfig for the list operation
	List          CommandConfig `json:"list,omitempty"`
	ListSeparator string        `json:"separator,omitempty"`
	// Exists CommandConfig for the exists operation
	Exists CommandConfig `json:"exists,omitempty"`
	// Metadata CommandConfig for the metadata operation
	Metadata CommandConfig `json:"metadata,omitempty"`

	// Environment variables for commands
	Environment map[string]string `json:"environment,omitempty"`

	// Timeout duration string for command execution
	Timeout string `json:"timeout,omitempty"`

	// WorkingDir for command execution
	WorkingDir string `json:"working_dir,omitempty"`
}

ExternalConfig contains external (cli command-based) vault configuration

func (*ExternalConfig) Validate

func (c *ExternalConfig) Validate() error

type ExternalVaultProvider

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

func NewExternalVaultProvider added in v0.2.0

func NewExternalVaultProvider(cfg *Config) (*ExternalVaultProvider, error)

func (*ExternalVaultProvider) Close

func (v *ExternalVaultProvider) Close() error

func (*ExternalVaultProvider) DeleteSecret

func (v *ExternalVaultProvider) DeleteSecret(key string) error

func (*ExternalVaultProvider) GetSecret

func (v *ExternalVaultProvider) GetSecret(key string) (Secret, error)

func (*ExternalVaultProvider) HasSecret

func (v *ExternalVaultProvider) HasSecret(key string) (bool, error)

func (*ExternalVaultProvider) ID

func (v *ExternalVaultProvider) ID() string

func (*ExternalVaultProvider) ListSecrets

func (v *ExternalVaultProvider) ListSecrets() ([]string, error)

func (*ExternalVaultProvider) Metadata added in v0.2.0

func (v *ExternalVaultProvider) Metadata() Metadata

func (*ExternalVaultProvider) SetExecutionFunc added in v0.2.0

func (v *ExternalVaultProvider) SetExecutionFunc(
	fn func(ctx context.Context, cmd, input, dir string, envList []string) (string, error),
)

func (*ExternalVaultProvider) SetSecret

func (v *ExternalVaultProvider) SetSecret(key string, value Secret) error

type IdentityResolver

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

func NewIdentityResolver

func NewIdentityResolver(sources []IdentitySource) *IdentityResolver

func (*IdentityResolver) ResolveIdentities

func (r *IdentityResolver) ResolveIdentities() ([]age.Identity, error)

type IdentitySource

type IdentitySource struct {
	// Type of identity source
	// Must be one of: "env", "file"
	Type string `json:"type"`
	// Path to the identity file (for "file" type)
	Path string `json:"fullPath,omitempty"`
	// Environment variable name (for "env" type)
	Name string `json:"name,omitempty"`
}

IdentitySource represents a source for the local vault identity keys

type KeyResolver

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

func NewKeyResolver

func NewKeyResolver(sources []KeySource) *KeyResolver

func (*KeyResolver) ResolveKeys

func (r *KeyResolver) ResolveKeys() ([]string, error)

func (*KeyResolver) TryDecrypt

func (r *KeyResolver) TryDecrypt(encryptedData string) (string, string, error)

type KeySource

type KeySource struct {
	// Type of data encryption key source
	// Must be one of: "env", "file"
	Type string `json:"type"`
	// Path to the identity file (for "file" type)
	Path string `json:"fullPath,omitempty"`
	// Environment variable name (for "env" type)
	Name string `json:"name,omitempty"`
}

KeySource represents a source for the local vault encryption keys

type KeyringConfig added in v0.2.0

type KeyringConfig struct {
	// Service name used for keyring operations
	Service string `json:"service"`
}

KeyringConfig contains keyring vault configuration

func (*KeyringConfig) Validate added in v0.2.0

func (c *KeyringConfig) Validate() error

type KeyringVault added in v0.2.0

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

KeyringVault manages operations on a keyring-based vault that stores secrets in the system keyring.

func NewKeyringVault added in v0.2.0

func NewKeyringVault(cfg *Config) (*KeyringVault, error)

func (*KeyringVault) Close added in v0.2.0

func (v *KeyringVault) Close() error

func (*KeyringVault) DeleteSecret added in v0.2.0

func (v *KeyringVault) DeleteSecret(key string) error

func (*KeyringVault) GetSecret added in v0.2.0

func (v *KeyringVault) GetSecret(key string) (Secret, error)

func (*KeyringVault) HasSecret added in v0.2.0

func (v *KeyringVault) HasSecret(key string) (bool, error)

func (*KeyringVault) ID added in v0.2.0

func (v *KeyringVault) ID() string

func (*KeyringVault) ListSecrets added in v0.2.0

func (v *KeyringVault) ListSecrets() ([]string, error)

func (*KeyringVault) Metadata added in v0.2.0

func (v *KeyringVault) Metadata() Metadata

func (*KeyringVault) SetSecret added in v0.2.0

func (v *KeyringVault) SetSecret(key string, secret Secret) error

type Metadata

type Metadata struct {
	Created      time.Time `json:"created"`
	LastModified time.Time `json:"lastModified"`
	RawData      string    `json:"data,omitempty"`
}

type Option

type Option func(*Config)

func WithAESKeyFromEnv

func WithAESKeyFromEnv(envVar string) Option

WithAESKeyFromEnv specifies to retrieve the AES key from an environment variable

func WithAESKeyFromFile

func WithAESKeyFromFile(path string) Option

WithAESKeyFromFile specifies to retrieve the AES key from a file

func WithAESPath

func WithAESPath(path string) Option

WithAESPath sets the AES vault storage path

func WithAgeIdentityFromEnv

func WithAgeIdentityFromEnv(envVar string) Option

WithAgeIdentityFromEnv specifies to retrieve the age identity from an environment variable

func WithAgeIdentityFromFile

func WithAgeIdentityFromFile(path string) Option

WithAgeIdentityFromFile specifies to retrieve the age identity from a file

func WithAgePath

func WithAgePath(path string) Option

WithAgePath sets the age vault storage path

func WithAgeRecipients

func WithAgeRecipients(recipients ...string) Option

WithAgeRecipients sets the recipients for age vaults

func WithExternalConfig

func WithExternalConfig(cfg *ExternalConfig) Option

WithExternalConfig sets the external vault configuration. FOR TESTING PURPOSES ONLY. TODO: break this down when the external provider is fully implemented

func WithKeyringService added in v0.2.0

func WithKeyringService(service string) Option

WithKeyringService sets the keyring service name

func WithLocalPath

func WithLocalPath(path string) Option

WithLocalPath sets the local vault storage path (works for Age, AES, and Unencrypted based on provider type)

func WithProvider

func WithProvider(provider ProviderType) Option

WithProvider sets the vault provider type

func WithUnencryptedPath added in v0.2.0

func WithUnencryptedPath(path string) Option

WithUnencryptedPath sets the unencrypted vault storage path

type Provider

type Provider interface {
	GetSecret(key string) (Secret, error)
	SetSecret(key string, value Secret) error
	DeleteSecret(key string) error
	ListSecrets() ([]string, error)
	HasSecret(key string) (bool, error)

	// ID returns a unique identifier for this vault instance
	ID() string

	// Metadata returns vault metadata such as creation time
	Metadata() Metadata

	Close() error
}

type ProviderType

type ProviderType string
const (
	ProviderTypeAES256      ProviderType = "aes256"
	ProviderTypeAge         ProviderType = "age"
	ProviderTypeExternal    ProviderType = "external"
	ProviderTypeKeyring     ProviderType = "keyring"
	ProviderTypeUnencrypted ProviderType = "unencrypted"
)

type RecipientManager

type RecipientManager interface {
	AddRecipient(identity string) error
	RemoveRecipient(identity string) error
	ListRecipients() ([]string, error)
}

func HasRecipientManagement

func HasRecipientManagement(v Provider) (RecipientManager, bool)

type Secret

type Secret interface {
	// PlainTextString returns the decrypted value as a string
	PlainTextString() string

	// String returns a masked representation for display
	String() string

	// Bytes returns the raw byte representation of the secret
	Bytes() []byte

	// Zero securely clears the secret from memory
	Zero()
}

type SecretValue

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

func NewSecretValue

func NewSecretValue(value []byte) *SecretValue

func (*SecretValue) Bytes

func (s *SecretValue) Bytes() []byte

func (*SecretValue) PlainTextString

func (s *SecretValue) PlainTextString() string

func (*SecretValue) String

func (s *SecretValue) String() string

func (*SecretValue) Zero

func (s *SecretValue) Zero()

type SecureBytes

type SecureBytes []byte

SecureBytes is a wrapper around []byte that provides secure memory handling

func (SecureBytes) Copy

func (s SecureBytes) Copy() SecureBytes

Copy creates a secure copy of the bytes

func (*SecureBytes) Zero

func (s *SecureBytes) Zero()

Zero securely clears the byte slice

type UnencryptedConfig added in v0.2.0

type UnencryptedConfig struct {
	// Storage location for the vault file
	StoragePath string `json:"storage_path"`
}

UnencryptedConfig contains unencrypted (plain text) vault configuration

func (*UnencryptedConfig) Validate added in v0.2.0

func (c *UnencryptedConfig) Validate() error

type UnencryptedState added in v0.2.0

type UnencryptedState struct {
	Metadata `json:"metadata"`

	Version int               `json:"version"`
	ID      string            `json:"id"`
	Secrets map[string]string `json:"secrets"`
}

UnencryptedState represents the state of the unencrypted vault.

type UnencryptedVault added in v0.2.0

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

UnencryptedVault manages operations on an instance of an unencrypted vault that stores secrets in JSON format.

func NewUnencryptedVault added in v0.2.0

func NewUnencryptedVault(cfg *Config) (*UnencryptedVault, error)

func (*UnencryptedVault) Close added in v0.2.0

func (v *UnencryptedVault) Close() error

func (*UnencryptedVault) DeleteSecret added in v0.2.0

func (v *UnencryptedVault) DeleteSecret(key string) error

func (*UnencryptedVault) GetSecret added in v0.2.0

func (v *UnencryptedVault) GetSecret(key string) (Secret, error)

func (*UnencryptedVault) HasSecret added in v0.2.0

func (v *UnencryptedVault) HasSecret(key string) (bool, error)

func (*UnencryptedVault) ID added in v0.2.0

func (v *UnencryptedVault) ID() string

func (*UnencryptedVault) ListSecrets added in v0.2.0

func (v *UnencryptedVault) ListSecrets() ([]string, error)

func (*UnencryptedVault) Metadata added in v0.2.0

func (v *UnencryptedVault) Metadata() Metadata

func (*UnencryptedVault) SetSecret added in v0.2.0

func (v *UnencryptedVault) SetSecret(key string, secret Secret) error

type VaultPathError

type VaultPathError struct {
	Path string
	Err  error
}

func NewVaultPathError

func NewVaultPathError(path string) *VaultPathError

func (*VaultPathError) Error

func (e *VaultPathError) Error() string

func (*VaultPathError) Unwrap

func (e *VaultPathError) Unwrap() error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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