Documentation
¶
Overview ¶
Package keeper — audit bridge connecting Keeper to pkg/audit.
Index ¶
- Variables
- func DeriveKEK(masterKey, adminCred, salt []byte) ([]byte, error)
- func GenerateDEK() (*memguard.Enclave, error)
- func GenerateDEKSalt() ([]byte, error)
- func GlobalGetKey(key string) ([]byte, error)
- func GlobalStore(store *Keeper)
- func UnwrapDEK(wrapped, kek []byte) (*memguard.Enclave, error)
- func WithJack(cfg JackConfig) func(*Config)
- func WrapDEK(dek *memguard.Enclave, kek []byte) ([]byte, error)
- type AuditEvent
- type BackupInfo
- type BucketEvent
- type BucketSecurityPolicy
- type Chain
- func (m *Chain) AppendEvent(scheme, namespace, eventType string, details interface{}) error
- func (m *Chain) CreatePolicy(policy *BucketSecurityPolicy) error
- func (m *Chain) GetPolicy(scheme, namespace string) (*BucketSecurityPolicy, error)
- func (m *Chain) PruneEvents(scheme, namespace string, olderThan time.Duration, keepLastN int) error
- func (m *Chain) VerifyChainIntegrity(scheme, namespace string) error
- type Config
- type EncryptedMetadata
- type Envelope
- func (e *Envelope) Drop(scheme, namespace string)
- func (e *Envelope) DropAdminWrapped(registry map[string]*BucketSecurityPolicy)
- func (e *Envelope) DropAll()
- func (e *Envelope) HeldKeys() []string
- func (e *Envelope) Hold(scheme, namespace string, buf *memguard.LockedBuffer)
- func (e *Envelope) HoldBytes(scheme, namespace string, dek []byte)
- func (e *Envelope) HoldEnclave(scheme, namespace string, enc *memguard.Enclave) error
- func (e *Envelope) IsHeld(scheme, namespace string) bool
- func (e *Envelope) Retrieve(scheme, namespace string) (*memguard.LockedBuffer, error)
- type HSMProvider
- type Hooks
- type JackConfig
- type JackDoctor
- type JackPool
- type JackShutdown
- type Keeper
- func (s *Keeper) AddAdminToPolicy(scheme, namespace, adminID string, adminPassword []byte) error
- func (s *Keeper) Backup(w io.Writer) (BackupInfo, error)
- func (s *Keeper) BackupTo(w io.Writer) (int64, error)
- func (s *Keeper) Close() error
- func (s *Keeper) CompareAndSwap(key, oldValue, newValue string) error
- func (s *Keeper) CompareAndSwapNamespaced(namespace, key string, oldValue, newValue []byte) error
- func (s *Keeper) CompareAndSwapNamespacedFull(scheme, namespace, key string, oldValue, newValue []byte) error
- func (s *Keeper) Copy(key, fromNS, toNS string) error
- func (s *Keeper) CopyCrossBucket(key, fromScheme, fromNS, toScheme, toNS string, confirmDowngrade bool) error
- func (s *Keeper) CreateBucket(scheme, namespace string, level SecurityLevel, createdBy string) error
- func (s *Keeper) Delete(key string) error
- func (s *Keeper) DeleteBucket(scheme, namespace string) error
- func (s *Keeper) DeleteNamespace(namespace string) error
- func (s *Keeper) DeleteNamespaced(namespace, key string) error
- func (s *Keeper) DeleteNamespacedFull(scheme, namespace, key string) error
- func (s *Keeper) DeleteScheme(scheme string) error
- func (s *Keeper) DeriveMaster(passphrase []byte) (*Master, error)
- func (s *Keeper) Exists(key string) (bool, error)
- func (s *Keeper) ExistsNamespaced(namespace, key string) (bool, error)
- func (s *Keeper) ExistsNamespacedFull(scheme, namespace, key string) (bool, error)
- func (s *Keeper) Get(key string) ([]byte, error)
- func (s *Keeper) GetBytes(key string) ([]byte, error)
- func (s *Keeper) GetBytesNamespaced(namespace, key string) ([]byte, error)
- func (s *Keeper) GetNamespaced(namespace, key string) ([]byte, error)
- func (s *Keeper) GetNamespacedFull(scheme, namespace, key string) ([]byte, error)
- func (s *Keeper) GetPolicy(scheme, namespace string) (*BucketSecurityPolicy, error)
- func (s *Keeper) GetString(key string) (string, error)
- func (s *Keeper) GetStringNamespaced(namespace, key string) (string, error)
- func (s *Keeper) IsBucketUnlocked(scheme, namespace string) bool
- func (s *Keeper) IsLocked() bool
- func (s *Keeper) List() ([]string, error)
- func (s *Keeper) ListNamespace(namespace string) ([]string, error)
- func (s *Keeper) ListNamespacedFull(scheme, namespace string) ([]string, error)
- func (s *Keeper) ListNamespaces() ([]string, error)
- func (s *Keeper) ListNamespacesInSchemeFull(scheme string) ([]string, error)
- func (s *Keeper) ListPrefix(prefix string) ([]string, error)
- func (s *Keeper) ListPrefixNamespaced(namespace, prefix string) ([]string, error)
- func (s *Keeper) ListPrefixNamespacedFull(scheme, namespace, prefix string) ([]string, error)
- func (s *Keeper) ListSchemes() ([]string, error)
- func (s *Keeper) Lock() error
- func (s *Keeper) LockBucket(scheme, namespace string) error
- func (s *Keeper) Metrics() core.MetricsSnapshot
- func (s *Keeper) Move(key, fromNS, toNS string) error
- func (s *Keeper) MoveCrossBucket(key, fromScheme, fromNS, toScheme, toNS string, confirmDowngrade bool) error
- func (s *Keeper) NeedsAdminRekey(scheme, namespace string) (bool, error)
- func (s *Keeper) RegisterHSMProvider(scheme, namespace string, provider HSMProvider) error
- func (s *Keeper) RegisterScheme(name string, handler SchemeHandler) error
- func (s *Keeper) Rename(key, newKey string) error
- func (s *Keeper) RenameNamespaced(namespace, oldKey, newKey string) error
- func (s *Keeper) RenameNamespacedFull(scheme, namespace, oldKey, newKey string) error
- func (s *Keeper) RevokeAdmin(scheme, namespace, adminID string) error
- func (s *Keeper) Rotate(newPassphrase []byte) error
- func (s *Keeper) RotateAdminWrappedDEK(scheme, namespace, adminID string, adminPassword []byte) error
- func (s *Keeper) RotateSalt(passphrase []byte) error
- func (s *Keeper) Set(key string, value []byte) error
- func (s *Keeper) SetAuditFunc(...)
- func (s *Keeper) SetBytes(key string, value []byte) error
- func (s *Keeper) SetDefaultNamespace(ns string) error
- func (s *Keeper) SetDefaultScheme(scheme string) error
- func (s *Keeper) SetHooks(hooks Hooks)
- func (s *Keeper) SetNamespaced(namespace, key string, value []byte) error
- func (s *Keeper) SetNamespacedFull(scheme, namespace, key string, value []byte) error
- func (s *Keeper) SetString(key, value string) error
- func (s *Keeper) SetStringNamespaced(namespace, key, value string) error
- func (s *Keeper) Stats() (*StoreStats, error)
- func (s *Keeper) Unlock(passphrase []byte) error
- func (s *Keeper) UnlockBucket(scheme, namespace, adminID string, adminPassword []byte) error
- func (s *Keeper) UnlockDatabase(master *Master) error
- type Master
- type NamespaceStats
- type RotationWAL
- type SaltEntry
- type SaltStore
- type SchemeHandler
- type SchemeStats
- type Secret
- type SecurityLevel
- type StoreStats
Constants ¶
This section is empty.
Variables ¶
var ( ErrStoreLocked = errors.New("secret store is locked") ErrInvalidPassphrase = errors.New("invalid passphrase or admin credential") ErrKeyNotFound = errors.New("secret key not found") ErrNamespaceNotFound = errors.New("namespace not found") ErrNamespaceEmpty = errors.New("namespace cannot be empty") ErrNamespaceInvalid = errors.New("invalid namespace name") ErrSchemeInvalid = errors.New("invalid scheme name") ErrAlreadyUnlocked = errors.New("store already unlocked") ErrInvalidConfig = errors.New("invalid store configuration") ErrCASConflict = errors.New("compare-and-swap conflict: value changed") ErrMigrationFailed = errors.New("database migration failed") ErrMasterRequired = errors.New("master key required") ErrPolicyImmutable = errors.New("bucket policy is immutable after creation") ErrChainBroken = errors.New("audit chain integrity check failed") ErrPolicyNotFound = errors.New("bucket policy not found") ErrBucketLocked = errors.New("bucket is locked — call UnlockBucket first") ErrSecurityDowngrade = errors.New("security downgrade requires explicit confirmation") ErrRotationIncomplete = errors.New("incomplete key rotation detected: call Rotate again with the new passphrase") ErrAdminNotFound = errors.New("admin ID not found in bucket policy") ErrPolicySignature = errors.New("policy signature verification failed") ErrMetadataDecrypt = errors.New("metadata decryption failed") ErrHSMProviderNil = errors.New("LevelHSM and LevelRemote require a non-nil HSMProvider") ErrCheckLatency = errors.New("database read latency exceeded threshold") // ErrAuthFailed is returned for any authentication failure in UnlockBucket. // It deliberately does not distinguish between an unknown admin ID and a // wrong password to prevent admin ID enumeration (CWE-204 / CVSS 5.3). ErrAuthFailed = errors.New("authentication failed") )
Sentinel errors.
Functions ¶
func DeriveKEK ¶
DeriveKEK derives a Key Encryption Key from master key + admin credential + salt. Uses HKDF-SHA256. The KEK must be used immediately and then zeroed — never stored.
Neither masterKey alone nor adminCred alone can derive the KEK. Changing admin password requires only re-wrapping the DEK, not re-encrypting secrets.
func GenerateDEK ¶
GenerateDEK generates a fresh random 32-byte Data Encryption Key. Returns it sealed in a memguard Enclave — protected from birth.
func GenerateDEKSalt ¶
GenerateDEKSalt generates a fresh random salt for a new bucket's DEK.
func GlobalGetKey ¶
GlobalGetKey retrieves a secret from the global store.
func GlobalStore ¶
func GlobalStore(store *Keeper)
GlobalStore sets the process-wide default Keeper instance.
func UnwrapDEK ¶
UnwrapDEK decrypts a wrapped DEK. Returns it sealed in a new Enclave. kek is zeroed after use. Returns ErrInvalidPassphrase on authentication failure.
func WithJack ¶
func WithJack(cfg JackConfig) func(*Config)
WithJack returns an option that attaches Jack integration handles to the Config.
Types ¶
type AuditEvent ¶
AuditEvent is the public-facing audit record re-exported from pkg/audit.
type BackupInfo ¶
BackupInfo holds metadata about a completed backup.
type BucketEvent ¶
BucketEvent is an audit event (alias of pkg/audit.Event).
type BucketSecurityPolicy ¶
type BucketSecurityPolicy struct {
ID string `json:"id"`
Scheme string `json:"scheme"`
Namespace string `json:"namespace"`
Level SecurityLevel `json:"level"`
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by"`
EncryptionVersion int `json:"encryption_version"`
// LastRekeyed records when RotateAdminWrappedDEK last succeeded.
// A zero value means the bucket predates this field and should be treated
// as needing re-keying when NeedsAdminRekey is called after a salt rotation.
LastRekeyed time.Time `json:"last_rekeyed,omitempty"`
// LevelAdminWrapped only:
DEKSalt []byte `json:"dek_salt,omitempty"`
WrappedDEKs map[string][]byte `json:"wrapped_deks,omitempty"`
// HSMProvider is required for LevelHSM and LevelRemote buckets.
// It is excluded from JSON serialisation — callers must register it via
// Keeper.RegisterHSMProvider after opening the database.
HSMProvider HSMProvider `json:"-"`
// Handler provides optional pre/post-processing hooks for this bucket.
Handler SchemeHandler `json:"-"`
}
BucketSecurityPolicy is immutable after creation.
func (*BucketSecurityPolicy) HasAdmin ¶
func (p *BucketSecurityPolicy) HasAdmin(adminID string) bool
HasAdmin reports whether adminID has a wrapped DEK copy in this policy.
func (*BucketSecurityPolicy) Validate ¶
func (p *BucketSecurityPolicy) Validate() error
Validate checks policy constraints before creation.
type Chain ¶
type Chain struct {
// contains filtered or unexported fields
}
Chain manages immutable policy storage and append-only audit events.
func NewPolicyChainManager ¶
NewPolicyChainManager creates a new chain manager.
func (*Chain) AppendEvent ¶
AppendEvent adds a new audit event to the bucket's chain.
func (*Chain) CreatePolicy ¶
func (m *Chain) CreatePolicy(policy *BucketSecurityPolicy) error
CreatePolicy registers a new immutable bucket policy.
func (*Chain) GetPolicy ¶
func (m *Chain) GetPolicy(scheme, namespace string) (*BucketSecurityPolicy, error)
GetPolicy retrieves a bucket policy (read-only).
func (*Chain) PruneEvents ¶
PruneEvents removes old events; never prunes high-security buckets.
func (*Chain) VerifyChainIntegrity ¶
VerifyChainIntegrity checks the entire audit chain for a bucket.
type Config ¶
type Config struct {
DBPath string
KeyLen int
AutoLockInterval time.Duration
EnableAudit bool
DefaultScheme string
DefaultNamespace string
Logger *ll.Logger
Jack JackConfig
// AuditPruneInterval controls how often the scheduler prunes audit events.
// Set to 0 to disable automatic pruning.
AuditPruneInterval time.Duration
// AuditPruneOlderThan removes events older than this duration each prune cycle.
AuditPruneOlderThan time.Duration
// AuditPruneKeepLastN retains at least this many recent events regardless of age.
AuditPruneKeepLastN int
// DBLatencyThreshold is the maximum acceptable database read latency.
// Defaults to defaultDBLatencyThreshold when zero.
DBLatencyThreshold time.Duration
KDF crypt.KDF
NewCipher func(key []byte) (crypt.Cipher, error)
Argon2Time uint32
Argon2Memory uint32
Argon2Parallelism uint8
VerifyArgon2Time uint32
VerifyArgon2Memory uint32
VerifyArgon2Parallelism uint8
}
Config holds all configuration for a Keeper instance.
type EncryptedMetadata ¶
type EncryptedMetadata struct {
CreatedAt time.Time `msgpack:"ca"`
UpdatedAt time.Time `msgpack:"ua"`
AccessCount int `msgpack:"ac"`
LastAccess time.Time `msgpack:"la,omitempty"`
Version int `msgpack:"v"`
}
EncryptedMetadata holds per-secret metadata encrypted with a key derived from the bucket DEK. Inaccessible without the bucket key.
type Envelope ¶
type Envelope struct {
// contains filtered or unexported fields
}
Envelope is the in-memory secure vault for Data Encryption Keys (DEKs).
Every unlocked bucket has exactly one entry here. The DEK is sealed inside a memguard Enclave which:
- mlocks the memory so the OS never pages it to disk
- mprotects the pages read-only when not in active use
- zeros the memory on release
Replaces the previous plain-map bucketKeys — Go's GC gave no guarantee that key bytes would ever be zeroed.
func NewEnvelope ¶
func NewEnvelope() *Envelope
NewEnvelope creates an empty, ready-to-use Envelope.
func (*Envelope) Drop ¶
Drop removes the sealed DEK for a single bucket. The Enclave is dropped from the map; memguard cleans up on GC.
func (*Envelope) DropAdminWrapped ¶
func (e *Envelope) DropAdminWrapped(registry map[string]*BucketSecurityPolicy)
DropAdminWrapped removes DEKs for all buckets whose policy is LevelAdminWrapped. LevelPasswordOnly (system/vault://) buckets are intentionally preserved so background jobs keep running after an admin session times out.
func (*Envelope) DropAll ¶
func (e *Envelope) DropAll()
DropAll removes every DEK from the Envelope.
func (*Envelope) HeldKeys ¶
HeldKeys returns the scheme:namespace keys currently in the Envelope. Intended for status/introspection only.
func (*Envelope) Hold ¶
func (e *Envelope) Hold(scheme, namespace string, buf *memguard.LockedBuffer)
Hold seals a DEK into a memguard Enclave. buf is sealed (and thus destroyed) by this call — do not use it after.
func (*Envelope) HoldBytes ¶
HoldBytes seals raw key bytes into the Envelope, then zeros the source slice.
func (*Envelope) HoldEnclave ¶
HoldEnclave opens a sealed Enclave and places its contents into the Envelope. enc is consumed — the Envelope re-seals the data under its own map entry.
func (*Envelope) IsHeld ¶
IsHeld reports whether a DEK for this scheme/namespace is currently sealed.
func (*Envelope) Retrieve ¶
func (e *Envelope) Retrieve(scheme, namespace string) (*memguard.LockedBuffer, error)
Retrieve opens the Enclave and returns a LockedBuffer. The caller MUST call buf.Destroy() when done — typically via defer.
buf, err := env.Retrieve(scheme, ns)
if err != nil { return err }
defer buf.Destroy()
useBytes(buf.Bytes())
type HSMProvider ¶
type HSMProvider interface {
WrapDEK(dek []byte) ([]byte, error)
UnwrapDEK(wrapped []byte) ([]byte, error)
Ping(ctx context.Context) error
}
HSMProvider abstracts wrap/unwrap operations for LevelHSM and LevelRemote buckets. Implementations must be safe for concurrent use from multiple goroutines. Ping is used by the jack.Doctor health patient to verify provider liveness.
type Hooks ¶
type Hooks struct {
PreSet func(scheme, namespace, key string, value []byte) ([]byte, error)
PostGet func(scheme, namespace, key string, value []byte) ([]byte, error)
PreDelete func(scheme, namespace, key string) error
OnAudit func(action, scheme, namespace, key string, success bool, duration time.Duration)
}
Hooks injects custom logic at key lifecycle points.
type JackConfig ¶
type JackConfig struct {
Pool JackPool
Shutdown JackShutdown
Doctor JackDoctor
}
JackConfig carries optional Jack integration handles. All fields are optional; nil means keeper manages its own equivalent.
type JackDoctor ¶
type JackDoctor interface {
Add(p *jack.Patient) error
Remove(id string) bool
StopAll(timeout time.Duration)
}
JackDoctor is the subset of jack.Doctor that keeper uses for health monitoring. Add accepts *jack.Patient to match the concrete jack.Doctor.Add signature so that *jack.Doctor satisfies this interface without an adapter.
type JackPool ¶
type JackPool interface {
Do(fn func())
DoCtx(ctx context.Context, fn func(context.Context))
IsClosed() bool
}
JackPool is the subset of jack.Pool that keeper uses. Keeper never calls Shutdown — the pool lifecycle is owned by the caller.
type JackShutdown ¶
JackShutdown is the subset of jack.Shutdown that keeper uses.
type Keeper ¶
type Keeper struct {
// contains filtered or unexported fields
}
Keeper is the encrypted secret store.
Security model:
LevelPasswordOnly buckets (vault://):
Master key → Envelope at UnlockDatabase. Available immediately at startup; background jobs always have access.
LevelAdminWrapped buckets (keeper://):
Random DEK per bucket. DEK wrapped per-admin via WrapDEK(dek, HKDF(master‖adminPass, salt)). UnlockBucket(adminID, adminPassword) → Envelope. Reaper TTL drops these DEKs after inactivity when Jack is configured.
LevelHSM and LevelRemote buckets:
Random DEK generated at CreateBucket time, wrapped by the HSMProvider. UnlockDatabase automatically calls the provider to unwrap and seed the Envelope for all registered HSM/Remote buckets. Master key rotation does not re-encrypt these buckets — the DEK is provider-controlled.
func GlobalGet ¶
func GlobalGet() *Keeper
GlobalGet returns the process-wide default Keeper instance.
func (*Keeper) AddAdminToPolicy ¶
AddAdminToPolicy wraps the bucket DEK under a new admin's KEK and persists the updated policy.
func (*Keeper) Backup ¶
func (s *Keeper) Backup(w io.Writer) (BackupInfo, error)
Backup writes to w and returns BackupInfo.
func (*Keeper) BackupTo ¶
BackupTo streams a consistent, point-in-time hot backup of the encrypted database directly to w.
func (*Keeper) CompareAndSwap ¶
func (*Keeper) CompareAndSwapNamespaced ¶
func (*Keeper) CompareAndSwapNamespacedFull ¶
func (s *Keeper) CompareAndSwapNamespacedFull(scheme, namespace, key string, oldValue, newValue []byte) error
CompareAndSwapNamespacedFull atomically reads, compares, and replaces a value. The DEK is retrieved inside the transaction to avoid a stale-key window.
func (*Keeper) CopyCrossBucket ¶
func (s *Keeper) CopyCrossBucket(key, fromScheme, fromNS, toScheme, toNS string, confirmDowngrade bool) error
CopyCrossBucket copies a key between two buckets.
func (*Keeper) CreateBucket ¶
func (s *Keeper) CreateBucket(scheme, namespace string, level SecurityLevel, createdBy string) error
CreateBucket registers a new immutable bucket policy.
For LevelPasswordOnly: the bucket is accessible as soon as UnlockDatabase has been called. If the store is already unlocked when CreateBucket is called the bucket is seeded into the Envelope immediately.
For LevelAdminWrapped: the bucket is inaccessible until at least one admin is added via AddAdminToPolicy and then unlocked via UnlockBucket.
For LevelHSM and LevelRemote: the policy must carry a non-nil HSMProvider. The DEK is generated here, wrapped by the provider, and stored in WrappedDEKs.
func (*Keeper) DeleteBucket ¶
DeleteBucket removes a namespace bucket and all its contents.
func (*Keeper) DeleteNamespace ¶
func (*Keeper) DeleteNamespaced ¶
func (*Keeper) DeleteNamespacedFull ¶
DeleteNamespacedFull removes a secret with explicit scheme/namespace/key.
func (*Keeper) DeleteScheme ¶
DeleteScheme removes an entire scheme and all its namespaces.
func (*Keeper) DeriveMaster ¶
DeriveMaster derives a Master key from passphrase bytes using the configured KDF. The dummy timing code from the previous version is removed: Argon2 dominates the timing, making the failure path indistinguishable in practice.
func (*Keeper) ExistsNamespaced ¶
func (*Keeper) ExistsNamespacedFull ¶
ExistsNamespacedFull reports whether a key is present in the given bucket.
func (*Keeper) GetBytesNamespaced ¶
func (*Keeper) GetNamespaced ¶
func (*Keeper) GetNamespacedFull ¶
GetNamespacedFull retrieves a secret with explicit scheme/namespace/key.
func (*Keeper) GetPolicy ¶
func (s *Keeper) GetPolicy(scheme, namespace string) (*BucketSecurityPolicy, error)
GetPolicy returns a bucket's immutable policy.
func (*Keeper) GetStringNamespaced ¶
func (*Keeper) IsBucketUnlocked ¶
IsBucketUnlocked reports whether a bucket's DEK is in the Envelope.
func (*Keeper) ListNamespacedFull ¶
ListNamespacedFull returns all keys for the given scheme/namespace.
func (*Keeper) ListNamespaces ¶
func (*Keeper) ListNamespacesInSchemeFull ¶
ListNamespacesInSchemeFull returns all namespace names within a scheme.
func (*Keeper) ListPrefixNamespaced ¶
func (*Keeper) ListPrefixNamespacedFull ¶
ListPrefixNamespacedFull returns all keys matching prefix in the given bucket.
func (*Keeper) ListSchemes ¶
ListSchemes returns all scheme names in the database.
func (*Keeper) Lock ¶
Lock locks the store: drops all DEKs, wipes the master key, clears the audit signing key, and stops all background goroutines.
func (*Keeper) LockBucket ¶
LockBucket drops the DEK for a single bucket from the Envelope.
func (*Keeper) Metrics ¶
func (s *Keeper) Metrics() core.MetricsSnapshot
Metrics returns a snapshot of operational counters.
func (*Keeper) MoveCrossBucket ¶
func (s *Keeper) MoveCrossBucket(key, fromScheme, fromNS, toScheme, toNS string, confirmDowngrade bool) error
MoveCrossBucket moves a key between two buckets.
func (*Keeper) NeedsAdminRekey ¶
NeedsAdminRekey reports whether a LevelAdminWrapped bucket's wrapped DEKs were last re-keyed before the current master salt was generated. Returns false with no error for LevelPasswordOnly, LevelHSM, and LevelRemote buckets.
func (*Keeper) RegisterHSMProvider ¶
func (s *Keeper) RegisterHSMProvider(scheme, namespace string, provider HSMProvider) error
RegisterHSMProvider attaches an HSMProvider to an existing LevelHSM or LevelRemote policy in the registry. This must be called after Open and before UnlockDatabase so the provider is available when the bucket is automatically unlocked. It returns an error if the policy is not found or is not HSM/Remote level.
func (*Keeper) RegisterScheme ¶
func (s *Keeper) RegisterScheme(name string, handler SchemeHandler) error
RegisterScheme validates and registers a scheme name with an optional handler.
func (*Keeper) RenameNamespaced ¶
func (*Keeper) RenameNamespacedFull ¶
RenameNamespacedFull moves a key within an explicit bucket.
func (*Keeper) RevokeAdmin ¶
RevokeAdmin removes an admin's wrapped DEK copy from the policy. The bucket DEK and all secrets remain untouched.
func (*Keeper) Rotate ¶
Rotate re-derives the master key with a new passphrase and re-encrypts every LevelPasswordOnly secret. LevelAdminWrapped secrets use per-admin KEKs and are unaffected.
After the master key changes:
- The audit signing key is re-derived from the new master.
- A key-rotation checkpoint event is appended to every active audit chain, signed with the old key as the final event of the old epoch and verifiable by the new key as the first event of the new epoch.
Passphrase bytes are NOT zeroed by this method — the caller owns them.
func (*Keeper) RotateAdminWrappedDEK ¶
func (s *Keeper) RotateAdminWrappedDEK(scheme, namespace, adminID string, adminPassword []byte) error
RotateAdminWrappedDEK re-wraps the bucket DEK under a fresh per-bucket salt for the given admin, then updates LastRekeyed on the policy. The admin must authenticate with their current password to prove they hold a valid copy of the DEK before it is re-wrapped. After this call, only admins whose credentials were supplied here will have up-to-date wrapped copies. Other admins must call this method with their own credentials to update their copy.
func (*Keeper) RotateSalt ¶
RotateSalt generates a new KDF salt, re-derives the master key under it, re-encrypts all LevelPasswordOnly secrets, and updates the verification hash. The old salt is retained in the versioned salt store for audit purposes.
Salt rotation is independent of passphrase rotation. Call this periodically or whenever you want to ensure that a compromised salt cannot be used to accelerate offline attacks against a future passphrase breach.
passphrase must be the current passphrase — it is used to re-derive the master key under the new salt. It is NOT zeroed by this method. LevelAdminWrapped buckets are NOT re-keyed by this call because their DEKs use a per-bucket salt, not the master KDF salt. Call RotateAdminWrappedDEK separately after this method completes.
func (*Keeper) SetAuditFunc ¶
func (s *Keeper) SetAuditFunc(fn func(action, scheme, namespace, key string, success bool, duration time.Duration))
SetAuditFunc registers a callback invoked on every auditable operation.
func (*Keeper) SetDefaultNamespace ¶
SetDefaultNamespace sets the default namespace used when none is specified.
func (*Keeper) SetDefaultScheme ¶
SetDefaultScheme sets the default scheme used when none is specified.
func (*Keeper) SetNamespaced ¶
func (*Keeper) SetNamespacedFull ¶
SetNamespacedFull stores a secret with explicit scheme/namespace/key.
func (*Keeper) SetStringNamespaced ¶
func (*Keeper) Stats ¶
func (s *Keeper) Stats() (*StoreStats, error)
Stats returns aggregate statistics for all schemes and namespaces. Locked buckets contribute key counts and sizes but zero metadata.
func (*Keeper) Unlock ¶
Unlock derives a Master key from passphrase bytes and calls UnlockDatabase. Passphrase bytes are NOT zeroed by this method — the caller owns them.
func (*Keeper) UnlockBucket ¶
UnlockBucket unlocks a LevelAdminWrapped bucket. adminPassword is zeroed by this method.
func (*Keeper) UnlockDatabase ¶
UnlockDatabase unlocks the store with a pre-derived Master key.
All LevelPasswordOnly buckets are unlocked immediately via the Envelope. LevelAdminWrapped buckets require a separate UnlockBucket call. LevelHSM and LevelRemote buckets are unlocked automatically via their registered HSMProvider. The audit HMAC signing key is derived from the master and activated. Background tasks (auto-lock, prune scheduler, health patients) are started after unlock completes.
type Master ¶
type Master struct {
// contains filtered or unexported fields
}
Master encapsulates the master key for the secret store. It uses memguard for secure memory handling.
func NewMaster ¶
NewMaster creates a new Master from a raw key. The raw key is immediately sealed into an enclave and wiped from memory.
func (*Master) Bytes ¶
Bytes retrieves the master key as a byte slice. This creates a temporary copy that should be used immediately and not stored. The caller should call secureZero on the returned bytes when done.
type NamespaceStats ¶
type NamespaceStats struct {
Scheme string `json:"scheme"`
Name string `json:"name"`
KeyCount int64 `json:"key_count"`
TotalSize int64 `json:"total_size"`
AvgKeySize float64 `json:"avg_key_size"`
OldestKey time.Time `json:"oldest_key"`
NewestKey time.Time `json:"newest_key"`
TotalReads int64 `json:"total_reads"`
TotalWrites int64 `json:"total_writes"`
EncryptionVersion int `json:"encryption_version"`
SecurityLevel string `json:"security_level"`
}
NamespaceStats holds aggregate statistics for one namespace.
type RotationWAL ¶
type RotationWAL struct {
Status string `json:"status"`
OldKeyHash []byte `json:"old_hash"`
NewKeyHash []byte `json:"new_hash"`
StartedAt time.Time `json:"started"`
LastKey string `json:"last_key"`
SaltVersion int `json:"salt_ver"`
WrappedOldKey []byte `json:"wrapped_old_key"`
}
RotationWAL tracks the state of an in-progress key rotation. Written atomically before the first record is re-encrypted. On crash, UnlockDatabase reads this record and resumes automatically.
WrappedOldKey is the pre-rotation master key encrypted with the new master key using XChaCha20-Poly1305. It is the only safe way to carry the old key across a crash boundary without storing it in plaintext.
type SaltEntry ¶
type SaltEntry struct {
Version int `json:"v"`
Salt []byte `json:"s"`
CreatedAt time.Time `json:"ca"`
}
SaltEntry records one generation of the KDF salt.
type SaltStore ¶
SaltStore is the versioned salt container stored under metaSaltKey. CurrentVersion indexes into Entries. Old entries are retained as an audit trail and for crash-recovery during salt rotation.
type SchemeHandler ¶
type SchemeHandler interface {
PreSet(scheme, namespace, key string, value []byte) ([]byte, error)
PostGet(scheme, namespace, key string, value []byte) ([]byte, error)
OnDelete(scheme, namespace, key string) error
}
SchemeHandler allows custom pre/post processing per scheme.
type SchemeStats ¶
type SchemeStats struct {
Name string `json:"name"`
Namespaces []NamespaceStats `json:"namespaces"`
TotalKeys int64 `json:"total_keys"`
TotalSize int64 `json:"total_size"`
}
SchemeStats holds aggregate statistics for one scheme.
type Secret ¶
type Secret struct {
Ciphertext []byte `msgpack:"ct"`
EncryptedMeta []byte `msgpack:"em,omitempty"`
SchemaVersion int `msgpack:"sv"`
}
Secret is the on-disk record for a single key, encoded with msgpack. SchemaVersion is always currentSchemaVersion.
type SecurityLevel ¶
type SecurityLevel string
SecurityLevel defines the key-management model for a bucket.
const ( LevelPasswordOnly SecurityLevel = "password_only" LevelAdminWrapped SecurityLevel = "admin_wrapped" LevelHSM SecurityLevel = "hsm" LevelRemote SecurityLevel = "remote" )
SecurityLevel values for BucketSecurityPolicy.
type StoreStats ¶
type StoreStats struct {
Schemes []SchemeStats `json:"schemes"`
TotalKeys int64 `json:"total_keys"`
TotalSize int64 `json:"total_size"`
IsLocked bool `json:"is_locked"`
DefaultScheme string `json:"default_scheme"`
DefaultNamespace string `json:"default_namespace"`
AutoLockInterval time.Duration `json:"auto_lock_interval"`
TotalReads int64 `json:"total_reads"`
TotalWrites int64 `json:"total_writes"`
LastActivity time.Time `json:"last_activity"`
DBSize int64 `json:"db_size_bytes"`
StorageEfficiency float64 `json:"storage_efficiency"`
KeyDerivation string `json:"key_derivation"`
SaltVersion int `json:"salt_version"`
}
StoreStats is returned by Keeper.Stats.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
keeper
command
Command keeper is a standalone secret management CLI backed by keeper.Keeper.
|
Command keeper is a standalone secret management CLI backed by keeper.Keeper. |
|
pkg
|
|
|
audit
Package audit provides append-only tamper-evident audit chain storage.
|
Package audit provides append-only tamper-evident audit chain storage. |
|
crypt
Package crypt defines pluggable encryption and key-derivation interfaces.
|
Package crypt defines pluggable encryption and key-derivation interfaces. |
|
hsm
Package hsm provides HSMProvider implementations for use with keeper.
|
Package hsm provides HSMProvider implementations for use with keeper. |
|
remote
Package remote provides a configurable HTTPS-based HSMProvider that delegates DEK wrap and unwrap operations to any remote KMS service over TLS.
|
Package remote provides a configurable HTTPS-based HSMProvider that delegates DEK wrap and unwrap operations to any remote KMS service over TLS. |
|
store
Package store defines the storage abstraction used by keeper.
|
Package store defines the storage abstraction used by keeper. |
|
x
|
|
|
keepcmd
Package keepcmd provides reusable keeper command operations decoupled from any specific CLI framework or application.
|
Package keepcmd provides reusable keeper command operations decoupled from any specific CLI framework or application. |
|
keephandler
Package keephandler provides a router-agnostic HTTP handler that mounts keeper secret management endpoints onto any net/http compatible mux.
|
Package keephandler provides a router-agnostic HTTP handler that mounts keeper secret management endpoints onto any net/http compatible mux. |