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
- Variables
- func DecryptWithKey(envelope, aad, key []byte) ([]byte, error)
- func EncryptWithKey(plaintext, aad, key []byte) ([]byte, error)
- func Generate(ctx context.Context, provider Provider) (*Keyring, []Entry, error)
- func Sealed(b []byte) bool
- type Entry
- type Keyring
- func (r *Keyring) AuditHMACKey() ([]byte, string)
- func (r *Keyring) Decrypt(envelope, aad []byte) ([]byte, error)
- func (r *Keyring) Encrypt(plaintext, aad []byte) ([]byte, error)
- func (r *Keyring) MAC(message []byte) []byte
- func (r *Keyring) TokenSigningKey() []byte
- func (r *Keyring) TokenSigningKeys() [][]byte
- func (r *Keyring) VerifyMAC(mac, message []byte) error
- type Provider
- type Rewrapper
- type Service
- func (s *Service) Entries(ctx context.Context) ([]Entry, error)
- func (s *Service) LatestKEK() string
- func (s *Service) Probe(ctx context.Context) error
- func (s *Service) RefreshLatestKEK(ctx context.Context) string
- func (s *Service) Rewrap(ctx context.Context) ([]Entry, error)
- func (s *Service) Rotate(ctx context.Context) ([]Entry, error)
- func (s *Service) Run(ctx context.Context)
- func (s *Service) State() string
- type Store
- type Versioner
Constants ¶
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.
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 ¶
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") )
var ( ErrKeyService = errors.New("key service failure") ErrRotationConflict = errors.New("keyring rotation conflict") )
Functions ¶
func DecryptWithKey ¶
DecryptWithKey opens a version-1 environment-key envelope.
func EncryptWithKey ¶
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.
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 New ¶
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 ¶
AuditHMACKey is the active audit HMAC key and its version label, distinct from the signing key per ADR-0020.
func (*Keyring) Decrypt ¶
Decrypt opens an envelope with the DEK version it names, under the same AAD it was sealed with.
func (*Keyring) Encrypt ¶
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 ¶
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 ¶
TokenSigningKey is the active token signing key (PurposeTokenSigning).
func (*Keyring) TokenSigningKeys ¶
TokenSigningKeys returns every signing key newest first. Callers use the first for new tokens and retain the rest for the lifetime of older tokens.
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 ¶
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 (*Service) Probe ¶
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
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.