Skip to main content

key_vault/monitor/
mod.rs

1//! Layer 8 — Security monitor.
2//!
3//! A [`SecurityMonitor`] is the vault's outbound channel for anomaly events:
4//! repeated decryption failures, unusual access patterns, and threshold
5//! breaches. Monitor calls happen on the failure path only; the success path
6//! costs nothing.
7//!
8//! Built-in monitors (`NoMonitor`, `LogMonitor`, `MetricsMonitor`,
9//! `WebhookMonitor`, `CompositeMonitor`) arrive in Phase 0.8. This module
10//! currently defines the trait surface and the three event-context structs.
11
12use alloc::borrow::Cow;
13use alloc::string::String;
14use core::time::Duration;
15
16/// Context passed when a decryption attempt fails — wrong key, tampered
17/// ciphertext, etc.
18#[non_exhaustive]
19#[derive(Debug, Clone)]
20pub struct FailureContext {
21    /// Logical name of the key whose use produced the failure.
22    pub key_name: String,
23    /// Number of consecutive failures observed for this key, including this
24    /// one.
25    pub consecutive_failures: u32,
26    /// Time elapsed since the first failure in the current window.
27    pub window_elapsed: Duration,
28    /// Caller-supplied free-form note. Sanitized — never includes key bytes
29    /// or ciphertext.
30    pub note: Cow<'static, str>,
31}
32
33/// Context for a successful access that the monitor flagged as anomalous —
34/// unusual caller, unusual frequency, off-hours activity.
35#[non_exhaustive]
36#[derive(Debug, Clone)]
37pub struct AccessContext {
38    /// Logical name of the key that was accessed.
39    pub key_name: String,
40    /// Caller-supplied free-form note. Sanitized.
41    pub note: Cow<'static, str>,
42}
43
44/// Context for a configured threshold being crossed (e.g. N failures in M
45/// seconds).
46#[non_exhaustive]
47#[derive(Debug, Clone)]
48pub struct ThresholdContext {
49    /// Logical name of the key.
50    pub key_name: String,
51    /// Number of failures observed within the configured window.
52    pub failures_in_window: u32,
53    /// Width of the configured window.
54    pub window: Duration,
55    /// `true` if this breach has put the vault into lock-out state.
56    pub lockout_triggered: bool,
57}
58
59/// Outbound channel for anomaly events.
60///
61/// Implementations should treat monitor calls as advisory and fire-and-forget:
62/// the vault must not block on a monitor, must not crash if a monitor panics
63/// or returns an error, and must not retry. Implementations that need
64/// retry, queuing, or batching are expected to handle that internally
65/// (typically on a background thread).
66///
67/// # Implementor contract
68///
69/// - **Non-blocking.** Calls must return promptly. Network or disk work should
70///   be deferred to a background worker.
71/// - **No panics.** A panicking monitor implementation is a bug in the
72///   implementation, not the vault. Wrap fallible operations and absorb
73///   their errors.
74/// - **No key material in calls.** None of the context structs carry raw key
75///   bytes; do not introduce custom side-channels that do.
76/// - **`Send + Sync`.** Monitors are shared across threads.
77pub trait SecurityMonitor: Send + Sync {
78    /// Called when a decryption attempt fails.
79    fn on_decryption_failure(&self, ctx: &FailureContext);
80
81    /// Called when an access pattern looks anomalous to the configured
82    /// detector.
83    fn on_anomalous_access(&self, ctx: &AccessContext);
84
85    /// Called when a configured failure threshold is crossed.
86    fn on_threshold_breach(&self, ctx: &ThresholdContext);
87}