vault

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package vault is Flynn's credential store: a secret.Source that holds API keys and other credentials encrypted at rest, so a user enters a key once and it is never written to disk in plaintext, never echoed, and revealed only at the point of use (the model request's authorization header).

It has two backends behind one interface, tried in order. The OS keychain (Windows Credential Manager / DPAPI, macOS Keychain, Linux Secret Service) is preferred: the platform encrypts the secret under the user's login and the agent never sees the ciphertext. On a host with no keychain (a server, a container), the vault falls back to a passphrase-sealed file: the credentials are encrypted with XChaCha20-Poly1305 under a key derived from a passphrase with Argon2id, so the file is useless without the passphrase. Either way the plaintext exists only inside the process, as a secret.Text, for as long as a request needs it.

The honest limit: a bearer API key must be sent verbatim, so the process holds plaintext at the moment of the call. Encryption at rest defeats disk theft, backups, and other users; it does not defeat code already running as this user. Removing even that requires a broker that holds the key out of process, which is a separate, heavier tier.

Index

Constants

View Source
const DefaultService = "flynn"

DefaultService is the keychain service name Flynn stores credentials under.

Variables

View Source
var (
	// ErrBadPassphrase reports a wrong passphrase or a tampered sealed file: the
	// authenticated decryption failed, so no plaintext is returned.
	ErrBadPassphrase = errors.New("vault: wrong passphrase or corrupted vault")
	// ErrNoPassphrase reports that the sealed-file fallback is needed but no
	// passphrase was supplied (no keychain, and nothing to unlock the file with).
	ErrNoPassphrase = errors.New("vault: a passphrase is required but none was supplied")
)

Sentinel errors for the sealed-file fallback.

View Source
var ErrKeyNotFound = errors.New("vault: key not found in keyring")

ErrKeyNotFound reports that a key is absent from the keyring (distinct from the keyring being unavailable, which surfaces as a different error from the backend).

Functions

func EnvPassphrase

func EnvPassphrase(bool) (secret.Text, error)

EnvPassphrase reads the sealed-file passphrase from FLYNN_VAULT_PASSPHRASE. It is the default so a non-interactive run can unlock a file-backed vault; it returns ErrNoPassphrase when the variable is unset.

Types

type Keyring

type Keyring interface {
	// Get returns the secret stored under key, or ErrKeyNotFound if none is.
	Get(service, key string) (string, error)
	// Set stores secret under key, replacing any existing value.
	Set(service, key, secret string) error
	// Delete removes the secret under key. Removing an absent key is not an error.
	Delete(service, key string) error
}

Keyring is the OS-backed secret store the vault prefers: the platform keychain that encrypts at rest under the user's login (Windows Credential Manager / DPAPI, macOS Keychain, Linux Secret Service). It is abstracted as an interface so the vault can run against a fake in tests and so a host with no keychain falls back to the passphrase-sealed file. A value stored here never touches the agent's disk in plaintext; the OS holds and guards it.

func OSKeyring

func OSKeyring() Keyring

OSKeyring returns the platform keychain as a Keyring, with each operation bounded by keychainOpTimeout so a stuck keychain never hangs the process. On a host with no keychain service its operations fail, and the vault falls back to the sealed file.

type Option

type Option func(*Store)

Option configures a Store.

func WithKeyring

func WithKeyring(kr Keyring) Option

WithKeyring overrides the OS keychain backend, for tests or to disable it.

func WithPassphrase

func WithPassphrase(p Passphrase) Option

WithPassphrase sets how the sealed-file fallback obtains its passphrase. The default reads the FLYNN_VAULT_PASSPHRASE environment variable; a CLI supplies a terminal prompt instead.

func WithService

func WithService(name string) Option

WithService overrides the keychain service name (default DefaultService).

type Passphrase

type Passphrase func(newVault bool) (secret.Text, error)

Passphrase supplies the passphrase that unlocks the sealed-file fallback. It is called only when the OS keychain is unavailable. newVault is true when a vault file is being created, so an interactive implementation can confirm the new passphrase, and false when an existing file is being opened.

type Store

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

Store is the credential vault. It implements secret.Source (Lookup) for the read path the provider uses, and adds Set and Delete for the management commands. It is safe for sequential use by a CLI; it is not designed for concurrent writers.

func New

func New(dir string, opts ...Option) *Store

New builds a Store. The sealed-file fallback lives under dir; the OS keychain is used when available. By default the fallback passphrase is read from the environment, so a non-interactive run can unlock a file-backed vault. Setting FLYNN_VAULT_FILE forces the sealed-file backend and never touches the OS keychain (see forceFileVault); an explicit WithKeyring still overrides it, because options are applied after the default is chosen.

func (*Store) Delete

func (s *Store) Delete(_ context.Context, ref string) error

Delete removes a credential from both backends, so a stale sealed-file copy cannot resurrect a value removed from the keychain. Removing an absent credential is not an error.

func (*Store) Lookup

func (s *Store) Lookup(_ context.Context, ref string) (secret.Text, error)

Lookup resolves a credential reference to its value, implementing secret.Source. It consults the keychain first; if the keychain is the active backend the file is not touched, so a desktop lookup never prompts for a passphrase. Only when the keychain is unavailable does it open the sealed file. An absent credential returns secret.ErrNotFound.

func (*Store) Set

func (s *Store) Set(_ context.Context, ref string, value secret.Text) error

Set stores a credential. It writes to the keychain when available (the OS encrypts it); otherwise it adds the value to the passphrase-sealed file. The value is taken as a secret.Text and exposed only to hand it to the backend.

Jump to

Keyboard shortcuts

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