keyring

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MPL-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package keyring implements encryption at rest (ADR-0024): a keyring of locally generated data-encryption keys held in memory, each stored wrapped by an external key service's key-encryption key. The external service is a startup and rotation dependency, never a write-path one — per-write encryption and MAC verification are purely local.

Index

Constants

View Source
const (
	PurposePayload      = "payload"
	PurposeIntegrity    = "integrity"
	PurposeTokenSigning = "token_signing"
	PurposeAuditHMAC    = "audit_hmac"
)

Key purposes. Distinct entries with independent rotation: ADR-0020 requires the audit key be distinct from the signing key, and payload confidentiality and row integrity are different jobs.

View Source
const ProviderEnv = "DFBG_KEY_PROVIDER"

ProviderEnv selects the key provider. Empty means encryption at rest is not configured; the mode marker makes that a permanent property of the instance at first boot (ADR-0024).

Variables

View Source
var (
	// ErrDecrypt covers every decryption failure — wrong AAD, truncated or
	// tampered ciphertext, unknown key version. One error, deliberately: the
	// distinctions matter to an investigator reading logs, not to a caller
	// deciding what to serve, and AES-GCM itself does not say why a tag failed.
	ErrDecrypt = errors.New("payload decryption failed")
	// ErrMAC reports a row whose integrity MAC is absent or does not verify.
	ErrMAC = errors.New("row integrity verification failed")
)
View Source
var (
	ErrKeyService       = errors.New("key service failure")
	ErrRotationConflict = errors.New("keyring rotation conflict")
)

Functions

func DecryptWithKey

func DecryptWithKey(envelope, aad, key []byte) ([]byte, error)

DecryptWithKey opens a version-1 environment-key envelope.

func EncryptWithKey

func EncryptWithKey(plaintext, aad, key []byte) ([]byte, error)

EncryptWithKey seals a payload with an environment-supplied AES-256 key using the same versioned envelope as Keyring.Encrypt. Version 1 is the sole environment-key version; keyring-backed deployments carry their rotations in the wrapped keyring instead.

func Generate

func Generate(ctx context.Context, provider Provider) (*Keyring, []Entry, error)

Generate mints a fresh key set locally (crypto/rand — DEK generation is deliberately not the provider's job, ADR-0024) and wraps each entry for storage. The plaintext keys live in the returned Keyring and nowhere else.

func Sealed

func Sealed(b []byte) bool

Sealed reports whether stored bytes carry the envelope encoding — used by readers whose column legitimately holds either a plaintext default or a sealed payload.

Types

type Entry

type Entry struct {
	Purpose   string
	Version   uint32
	Wrapped   []byte
	KEKRef    string
	WrappedAt time.Time
}

Entry is one stored keyring row: a wrapped key and the KEK reference that wrapped it (which KEK version, so rotation knows what still needs rewrapping).

type Keyring

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

Keyring holds the unwrapped keys in memory. Built once at startup; if the provider is unreachable then, the instance refuses to serve — sealed, in Vault's vocabulary — and per-write operations never call out.

func Load

func Load(ctx context.Context, provider Provider, entries []Entry) (*Keyring, error)

Load unwraps stored entries into a usable keyring.

func New

func New(keys map[string]map[uint32][]byte) (*Keyring, error)

New assembles a keyring from unwrapped keys. Every purpose must be present: a partial keyring would serve some guarantees and silently drop others.

func (*Keyring) AuditHMACKey

func (r *Keyring) AuditHMACKey() ([]byte, string)

AuditHMACKey is the active audit HMAC key and its version label, distinct from the signing key per ADR-0020.

func (*Keyring) Decrypt

func (r *Keyring) Decrypt(envelope, aad []byte) ([]byte, error)

Decrypt opens an envelope with the DEK version it names, under the same AAD it was sealed with.

func (*Keyring) Encrypt

func (r *Keyring) Encrypt(plaintext, aad []byte) ([]byte, error)

Encrypt seals plaintext under the active payload DEK with AES-256-GCM, binding the additional authenticated data — tenant and row identity — so a valid ciphertext moved to another row or tenant fails to decrypt. Envelope: magic | key version (uint32 BE) | nonce | ciphertext+tag.

func (*Keyring) MAC

func (r *Keyring) MAC(message []byte) []byte

MAC authenticates a row: HMAC-SHA256 over the caller's canonical message (which must include tenant and row identity, the same binding Encrypt gets from AAD), prefixed magic | key version.

func (*Keyring) TokenSigningKey

func (r *Keyring) TokenSigningKey() []byte

TokenSigningKey is the active token signing key (PurposeTokenSigning).

func (*Keyring) TokenSigningKeys

func (r *Keyring) TokenSigningKeys() [][]byte

TokenSigningKeys returns every signing key newest first. Callers use the first for new tokens and retain the rest for the lifetime of older tokens.

func (*Keyring) VerifyMAC

func (r *Keyring) VerifyMAC(mac, message []byte) error

VerifyMAC checks a stored MAC against the recomputed message. An absent MAC fails: on an encrypted deployment a row without one was not written by this application, which is exactly what the check exists to catch.

type Provider

type Provider interface {
	// Wrap encrypts a plaintext DEK, returning the opaque blob to store and a
	// reference identifying the KEK version that produced it.
	Wrap(ctx context.Context, plaintext []byte) (blob []byte, kekRef string, err error)
	// Unwrap reverses Wrap using the KEK version the blob names.
	Unwrap(ctx context.Context, blob []byte, kekRef string) ([]byte, error)
}

Provider wraps and unwraps DEKs with an external key-encryption key.

Two methods only, deliberately: DEK generation stays local (crypto/rand), and native rewrap is an optional capability because not every provider has a server-side equivalent (ADR-0024).

func ProviderFromEnvironment

func ProviderFromEnvironment(ctx context.Context) (Provider, error)

ProviderFromEnvironment builds the configured provider, or returns nil when none is configured. DFBG_ variables are the documented configuration surface; provider-native environment remains an escape hatch, with DFBG_ precedence.

type Rewrapper

type Rewrapper interface {
	Rewrap(ctx context.Context, blob []byte, kekRef string) ([]byte, string, error)
}

Rewrapper is the optional server-side rewrap capability. Provider remains the portable two-method contract; providers without this capability use an unwrap-then-wrap fallback.

type Service

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

Service owns runtime keyring maintenance and its remembered key-service health. Startup seeds healthy because Load has just unwrapped every entry.

func NewService

func NewService(provider Provider, store Store, ring *Keyring, logger *slog.Logger) *Service

func (*Service) Entries

func (s *Service) Entries(ctx context.Context) ([]Entry, error)

func (*Service) LatestKEK added in v0.3.0

func (s *Service) LatestKEK() string

func (*Service) Probe

func (s *Service) Probe(ctx context.Context) error

Probe performs the same real unwrap required during startup, then adopts any versions created by another replica. Database errors do not alter this key-service-only state.

func (*Service) RefreshLatestKEK added in v0.3.0

func (s *Service) RefreshLatestKEK(ctx context.Context) string

RefreshLatestKEK re-reads the key service's current KEK version and returns it. Reads serve the rewrap gate, so they cannot lean on the remembered heartbeat value: a KEK rotated at the key service moments ago must enable rewrap on the next screen refresh, not up to a heartbeat later.

func (*Service) Rewrap

func (s *Service) Rewrap(ctx context.Context) ([]Entry, error)

func (*Service) Rotate

func (s *Service) Rotate(ctx context.Context) ([]Entry, error)

func (*Service) Run

func (s *Service) Run(ctx context.Context)

Run probes after each fixed heartbeat interval with uniform jitter.

func (*Service) State

func (s *Service) State() string

type Store

type Store interface {
	ListKeyringEntries(context.Context) ([]Entry, error)
	CreateKeyringEntries(context.Context, []Entry, time.Time) (bool, error)
	RewrapKeyringEntries(context.Context, []Entry, time.Time) error
}

Store is the persistence needed by runtime keyring operations.

type Versioner added in v0.3.0

type Versioner interface {
	LatestKEK(ctx context.Context) (string, error)
}

Versioner reports the key service's current KEK version.

Jump to

Keyboard shortcuts

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