secrets

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package secrets implements VORTEX's encrypted secret store (build plan M3.2): a key-value store for arbitrary secret strings (database passwords, API keys, JWT secrets) encrypted at rest with XChaCha20-Poly1305. It is distinct from the vtls cert store — that holds TLS certificates; this holds secret values that are injected into managed processes at runtime and never written to config or disk in plaintext (Non-Negotiable Rule #2).

Index

Constants

View Source
const RotationWarningWindow = 7 * 24 * time.Hour

RotationWarningWindow is how far ahead of an expiry or rotation deadline DueForRotation starts reporting true.

Variables

This section is empty.

Functions

func InjectEnv

func InjectEnv(store *SecretStore, keys, existing []string) ([]string, error)

InjectEnv resolves the secrets named by keys and merges them into a copy of existing (os.Environ format: "KEY=value"). A secret value overrides any existing entry with the same key. The input slice is not modified.

func Resolve

func Resolve(store *SecretStore, keys []string) (map[string]string, error)

Resolve looks up every key in keys and returns a map of key→decrypted value. Resolution is all-or-nothing: if any key is missing (or fails to decrypt), it returns an error naming the offending key and no partial map.

func ResolveAdapter

func ResolveAdapter(ctx context.Context, a Adapter, keys []string) (map[string]string, error)

ResolveAdapter is the Adapter-based counterpart of Resolve: it looks up every key through any secret backend (local or external). Resolution is all-or-nothing, naming the first missing or failing key.

func ValidateKeys

func ValidateKeys(keys []string) error

ValidateKeys checks that every name in keys is a legal secret name. It returns an error listing all invalid names, or nil if all are valid.

func ValidateName

func ValidateName(name string) error

ValidateName reports whether name is a legal secret name (alphanumeric and underscore only).

Types

type AWSSSMAdapter

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

AWSSSMAdapter is a secret Adapter backed by AWS SSM Parameter Store, talking to the JSON-1.1 API directly with a minimal SigV4 signer (no AWS SDK).

func (*AWSSSMAdapter) Delete

func (a *AWSSSMAdapter) Delete(ctx context.Context, name string) error

Delete removes the named parameter. It is idempotent (ParameterNotFound is not an error).

func (*AWSSSMAdapter) Get

func (a *AWSSSMAdapter) Get(ctx context.Context, name string) (string, error)

Get returns the value of the named parameter (with the prefix applied).

func (*AWSSSMAdapter) List

func (a *AWSSSMAdapter) List(ctx context.Context) ([]string, error)

List returns parameter names under the prefix (with the prefix stripped).

func (*AWSSSMAdapter) Ping

func (a *AWSSSMAdapter) Ping(ctx context.Context) error

Ping performs a lightweight authenticated call to confirm connectivity. Any HTTP response (even an auth/permission error) proves the endpoint is reachable; only a network failure is treated as unreachable.

func (*AWSSSMAdapter) Set

func (a *AWSSSMAdapter) Set(ctx context.Context, name, value string) error

Set stores value as a SecureString parameter, overwriting any existing one.

type AWSSSMConfig

type AWSSSMConfig struct {
	Region    string // AWS region
	Prefix    string // parameter path prefix; default "/vortex/"
	AccessKey string // from env AWS_ACCESS_KEY_ID
	SecretKey string // from env AWS_SECRET_ACCESS_KEY
}

AWSSSMConfig configures the AWS SSM Parameter Store adapter.

type Adapter

type Adapter interface {
	Get(ctx context.Context, name string) (string, error)
	Set(ctx context.Context, name, value string) error
	List(ctx context.Context) ([]string, error)
	Delete(ctx context.Context, name string) error
	// Ping checks connectivity to the backend, returning nil when healthy.
	Ping(ctx context.Context) error
}

Adapter is a pluggable secret backend. The local store and the external providers (Vault, AWS SSM, GCP Secret Manager) all satisfy it, so the rest of VORTEX resolves secrets through one interface regardless of where they live.

func NewAWSSSMAdapter

func NewAWSSSMAdapter(cfg AWSSSMConfig) (Adapter, error)

NewAWSSSMAdapter builds an AWSSSMAdapter. Region is required; Prefix defaults to "/vortex/".

func NewAdapter

func NewAdapter(cfg AdapterConfig) (Adapter, error)

NewAdapter constructs the Adapter selected by cfg.Kind, validating that the fields required for that backend are present.

func NewGCPSMAdapter

func NewGCPSMAdapter(cfg GCPSMConfig) (Adapter, error)

NewGCPSMAdapter builds a GCPSMAdapter. ProjectID is required; Prefix defaults to "vortex-". If CredFile is set it is loaded as a service-account JSON; otherwise the GCE metadata server is used for tokens.

func NewVaultAdapter

func NewVaultAdapter(cfg VaultConfig) (Adapter, error)

NewVaultAdapter builds a VaultAdapter. Address is required; MountPath defaults to "secret" and Prefix to "vortex/".

type AdapterConfig

type AdapterConfig struct {
	Kind   string // "local" | "vault" | "aws-ssm" | "gcp-sm"
	Local  *SecretStore
	Vault  VaultConfig
	AWSSSM AWSSSMConfig
	GCPSM  GCPSMConfig
}

AdapterConfig selects and configures a secret backend.

type GCPSMAdapter

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

GCPSMAdapter is a secret Adapter backed by GCP Secret Manager's REST API, implemented directly over net/http (no google.golang.org SDK). Auth is via an OAuth2 access token obtained either from a service-account JSON (signed JWT exchanged for a token) or, when no credentials file is given, the GCE metadata server.

func (*GCPSMAdapter) Delete

func (a *GCPSMAdapter) Delete(ctx context.Context, name string) error

Delete removes the secret and all its versions. It is idempotent (404 is not an error).

func (*GCPSMAdapter) Get

func (a *GCPSMAdapter) Get(ctx context.Context, name string) (string, error)

Get returns the latest enabled version's payload for name.

func (*GCPSMAdapter) List

func (a *GCPSMAdapter) List(ctx context.Context) ([]string, error)

List returns secret names under the prefix (with the prefix stripped).

func (*GCPSMAdapter) Ping

func (a *GCPSMAdapter) Ping(ctx context.Context) error

Ping confirms connectivity by obtaining a token and listing secrets.

func (*GCPSMAdapter) Set

func (a *GCPSMAdapter) Set(ctx context.Context, name, value string) error

Set creates the secret (ignoring AlreadyExists) and adds a new version with the base64-encoded value as payload.

type GCPSMConfig

type GCPSMConfig struct {
	ProjectID string // GCP project ID
	Prefix    string // secret name prefix; default "vortex-"
	CredFile  string // path to a service account JSON, or "" for ADC/metadata
}

GCPSMConfig configures the GCP Secret Manager adapter.

type LocalAdapter

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

LocalAdapter adapts the on-disk encrypted SecretStore to the Adapter interface. It is always available, so Ping never fails.

func NewLocalAdapter

func NewLocalAdapter(store *SecretStore) *LocalAdapter

NewLocalAdapter wraps store in an Adapter.

func (*LocalAdapter) Delete

func (a *LocalAdapter) Delete(_ context.Context, name string) error

func (*LocalAdapter) Get

func (a *LocalAdapter) Get(_ context.Context, name string) (string, error)

func (*LocalAdapter) List

func (a *LocalAdapter) List(_ context.Context) ([]string, error)

func (*LocalAdapter) Ping

func (a *LocalAdapter) Ping(_ context.Context) error

Ping always succeeds: the local store is on the same host.

func (*LocalAdapter) Set

func (a *LocalAdapter) Set(_ context.Context, name, value string) error

type RotationAlert added in v0.3.0

type RotationAlert struct {
	Name     string
	Expired  bool      // true: past expiry; false: rotation due
	Deadline time.Time // the expiry or rotation deadline that triggered this
}

RotationAlert describes one secret needing operator attention: already expired, or due for rotation within the warning window.

type SecretMetadata added in v0.3.0

type SecretMetadata struct {
	Name        string        `json:"name"`
	CreatedAt   time.Time     `json:"created_at"`
	ExpiresAt   time.Time     `json:"expires_at,omitzero"` // zero = never expires
	LastRotated time.Time     `json:"last_rotated"`
	RotateEvery time.Duration `json:"rotate_every,omitempty"` // 0 = manual only
	Version     int           `json:"version"`
}

SecretMetadata tracks a secret's lifecycle for expiry and rotation alerts (build plan M19).

type SecretStore

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

SecretStore persists secret values on disk, each encrypted with XChaCha20-Poly1305 (24-byte nonce). The encryption key is derived from caller-supplied key material via SHA-256.

func NewSecretStore

func NewSecretStore(path string, key []byte) (*SecretStore, error)

NewSecretStore opens (creating if needed) a secret store at path, deriving the 32-byte key from key material via SHA-256.

func (*SecretStore) Adapter

func (s *SecretStore) Adapter() Adapter

Adapter returns this store wrapped as a local Adapter, so callers can treat the on-disk store uniformly with the external secret backends.

func (*SecretStore) CanDecrypt added in v0.3.0

func (s *SecretStore) CanDecrypt() bool

CanDecrypt reports whether at least one stored secret decrypts with this store's key — a cheap probe to detect whether a store is on this key (used by migration to decide whether re-keying is needed).

func (*SecretStore) CheckRotation added in v0.3.0

func (s *SecretStore) CheckRotation() ([]RotationAlert, error)

CheckRotation scans every stored secret's metadata and returns alerts for expired and rotation-due secrets, for the startup check and notifications.

func (*SecretStore) Delete

func (s *SecretStore) Delete(name string) error

Delete removes the secret named name. It is idempotent: a missing secret is not an error.

func (*SecretStore) DueForRotation added in v0.3.0

func (s *SecretStore) DueForRotation(name string) (bool, error)

DueForRotation reports whether name is inside the warning window (7 days) of its expiry, or past LastRotated+RotateEvery minus the window when a rotation interval is set. Secrets without metadata are never due.

func (*SecretStore) Exists

func (s *SecretStore) Exists(name string) (bool, error)

Exists reports whether a secret named name is set, without decrypting it.

func (*SecretStore) Get

func (s *SecretStore) Get(name string) (string, error)

Get decrypts and returns the value stored under name. It returns os.ErrNotExist if no such secret is set.

func (*SecretStore) GetMetadata added in v0.3.0

func (s *SecretStore) GetMetadata(name string) (*SecretMetadata, error)

GetMetadata returns the lifecycle metadata for name, or os.ErrNotExist when the secret has none (set via plain Set, or never set).

func (*SecretStore) IsExpired added in v0.3.0

func (s *SecretStore) IsExpired(name string) (bool, error)

IsExpired reports whether name's expiry has passed. Secrets without metadata or without an ExpiresAt never expire.

func (*SecretStore) List

func (s *SecretStore) List() ([]string, error)

List returns the names of all stored secrets.

func (*SecretStore) Rekey added in v0.3.0

func (s *SecretStore) Rekey(newKey []byte) error

Rekey re-encrypts every stored secret from this store's current key to newKey, used by the master-key migration (production audit C1) to move legacy cluster-name-keyed stores onto the master-derived key. On success the store's in-memory key is updated to newKey. Metadata files are plaintext JSON and are left untouched. It is best-effort atomic per file: each secret is decrypted, re-encrypted, and rewritten; a mid-run failure leaves already-converted files on the new key and the rest on the old, but the returned error names the failure so the caller can retry.

func (*SecretStore) Set

func (s *SecretStore) Set(name, value string) error

Set encrypts value and writes it under name.

func (*SecretStore) SetWithMetadata added in v0.3.0

func (s *SecretStore) SetWithMetadata(name, value string, meta SecretMetadata) error

SetWithMetadata stores value under name (encrypted, like Set) and records lifecycle metadata beside it. Zero CreatedAt/LastRotated default to now; a zero Version auto-increments from the previous metadata (starting at 1).

type VaultAdapter

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

VaultAdapter is a secret Adapter backed by HashiCorp Vault's KV v2 engine, implemented directly over the HTTP API (no Vault SDK).

func (*VaultAdapter) Delete

func (v *VaultAdapter) Delete(ctx context.Context, name string) error

Delete removes name. It is idempotent (404 is not an error).

func (*VaultAdapter) Get

func (v *VaultAdapter) Get(ctx context.Context, name string) (string, error)

Get returns the value stored at name (the "value" field of the KV v2 entry).

func (*VaultAdapter) List

func (v *VaultAdapter) List(ctx context.Context) ([]string, error)

List returns the secret names under the prefix.

func (*VaultAdapter) Ping

func (v *VaultAdapter) Ping(ctx context.Context) error

Ping checks Vault health. 200 (active) and 429 (standby) both mean reachable.

func (*VaultAdapter) Set

func (v *VaultAdapter) Set(ctx context.Context, name, value string) error

Set writes value at name as the KV v2 "value" field.

type VaultConfig

type VaultConfig struct {
	Address   string // e.g. https://vault.example.com
	Token     string // Vault token (typically from env VAULT_TOKEN)
	MountPath string // KV mount path; default "secret"
	Prefix    string // key prefix; default "vortex/"
}

VaultConfig configures the HashiCorp Vault KV v2 adapter.

Jump to

Keyboard shortcuts

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