Skip to content

[auto-rotation feature] PR 4 - Notification system (SMTP email)#971

Open
Manuthor wants to merge 5 commits into
feat/key-rotation-schedulerfrom
feat/key-rotation-notifications
Open

[auto-rotation feature] PR 4 - Notification system (SMTP email)#971
Manuthor wants to merge 5 commits into
feat/key-rotation-schedulerfrom
feat/key-rotation-notifications

Conversation

@Manuthor

@Manuthor Manuthor commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the notification subsystem for key rotation events: a NotificationsStore
trait backed by SQL, an SMTP email notifier (via lettre), threshold-based dedup
for renewal warnings, and a REST API for reading notifications from the UI.

This is PR 4 of 4 in the key auto-rotation feature stack (depends on PR 3: #970):

develop
  ← PR 1  docs/key-autorotation-spec          (#968)
  ← PR 2  feat/key-rotation-ckms-ui            (#988)
  ← PR 3  feat/key-rotation-scheduler          (#970)
  ← PR 4  feat/key-rotation-notifications      ← this PR (#971)

What's included

NotificationsStore trait — crate/interfaces/src/stores/notifications_store.rs

Persistent notification log with four methods:

Method Description
insert() Persist a new notification event
list(owner) All notifications for a user
unread_count(owner) Count of unread notifications
mark_read(id) / mark_all_read(owner) Mark as read

Implemented for SQLite, PostgreSQL, and MySQL (crate/server_database/).
NoopNotificationsStore provided for the Redis-findex backend (#[cfg(feature = "non-fips")]).

SMTP email notifier — crate/server/src/notifications/email.rs

  • Sends HTML/plain-text emails on rotation_success, rotation_failure, and
    approaching_deadline events
  • Uses lettre 0.11 (async SMTP with TLS)
  • Failures are logged at warn! level and never block the rotation operation

SmtpConfigcrate/server/src/config/command_line/smtp_config.rs

[notifications.smtp]
host     = "smtp.example.com"
port     = 587
username = "kms-alerts@example.com"
password = "..."
from     = "kms-alerts@example.com"
to       = ["ops@example.com"]
starttls = true

RenewalNotificationStrategy

Configures the threshold days (default: [30, 7, 1]) at which renewal warnings
are emitted before a key's next scheduled rotation.

dispatch_renewal_warnings() — wired into auto_rotate.rs

  • Scans all keys with an active rotation policy
  • Computes days until next rotation
  • Emits a warning event only if not already warned at this threshold
    (rotate_last_warning_days attribute for dedup)

HTTP API — crate/server/src/routes/notifications.rs

Endpoint Description
GET /notifications List all notifications for the authenticated user
GET /notifications/unread/count Count of unread notifications
POST /notifications/{id}/read Mark a single notification as read
POST /notifications/read-all Mark all notifications as read

Dependencies added

  • lettre = "0.11" (async SMTP)
  • "0BSD" added to deny.toml allow list (required by quoted_printable,
    a transitive dep of lettre)

Breaking changes

None. Notifications are off by default (no SMTP config → no emails sent;
HTTP API always available).

Reviewer notes

  • The NotificationsStore is injected into KmsServer alongside the
    existing ObjectsStore — no global state.
  • The Redis-findex backend (non-fips feature) uses NoopNotificationsStore
    because Redis-findex has no relational schema.
  • 0BSD license addition to deny.toml is intentional and safe — it is the
    most permissive OSI license (no attribution required).
  • The NotificationsBell UI component (from PR 2: [auto-rotation feature] PR 2 - ckms and Web UI updates #988) is wired to the
    GET /notifications/unread/count endpoint introduced here.

@Manuthor Manuthor changed the title feat: add notifications infrastructure for key auto-rotation events [auto-rotation feature] feat: add notifications infrastructure for key auto-rotation events May 28, 2026
Manuthor and others added 4 commits May 29, 2026 16:02
Add comprehensive specification for scheduled key rotation covering:
- 6 rotation scenarios (plain, wrapping, wrapped, asymmetric, CoverCrypt, KEK)
- Rotation policy vendor attributes (x-rotate-interval, etc.)
- Server-side cron scheduler
- KMIP attribute tables (auto vs manual rotation semantics)
- Implementation roadmap (5 stacked PRs)

Ref: #900
…s + test vectors (#969)

* feat(rekey): implement symmetric key ReKey with wrapping key re-wrap

- Implement KMIP ReKey for symmetric keys with name transfer per §4.4
- Support re-wrapping dependent keys when a wrapping key is rekeyed
- Add find_wrapped_by() to ObjectsStore trait (SQLite, PostgreSQL, MySQL)
- Fix: transfer Name attribute from old to new key during ReKey
- Fix: error on self-wrap when wrapping_key_id is user-supplied
- Fix: bypass ownership check for server-configured KEK

Tested with 37 vector tests (9 symmetric + 27 keypair + 1 security)

* fix: consolidate rekey operations using trait

* feat: consolidate Recertify operation
Add a background thread that periodically checks which keys are due for
rotation and automatically rotates them. The scheduler supports:

- Symmetric keys via KMIP ReKey
- Asymmetric keys (RSA/EC/PQC) via new CreateKeyPair + cross-links
- CoverCrypt keys via ReKeyKeyPair (in-place rotation)
- Certificates via Certify (re-issuance)

New components:
- find_due_for_rotation() in ObjectsStore trait + SQLite/PostgreSQL/MySQL impls
- is_due_for_rotation() helper in locate_query.rs
- auto_rotate.rs: rotation logic per object type
- spawn_auto_rotation_cron() in cron.rs
- --auto-rotation-check-interval-secs CLI flag (default: 0 = disabled)

The rotation policy (rotate_interval, rotate_name, rotate_offset) is
transferred to the new key so the cycle continues. Old keys get
rotate_interval=0 and ReplacementObjectLink to the new key.
@Manuthor Manuthor force-pushed the feat/key-rotation-scheduler branch from 4e3e03c to f27b7e5 Compare May 29, 2026 14:03
- NotificationsStore trait + implementations (SQLite, PostgreSQL, MySQL)
- SMTP email notifier (lettre) for renewal warnings and rotation events
- SmtpConfig + RenewalNotificationStrategy configuration
- dispatch_renewal_warnings() background scanner with threshold-based dedup
- rotate_last_warning_days attribute to prevent duplicate warnings
- HTTP API: GET /notifications, GET /notifications/unread/count,
  POST /notifications/{id}/read, POST /notifications/read-all
- NoopNotificationsStore for Redis-findex backend
- Allow 0BSD license (quoted_printable, transitive dep of lettre)
@Manuthor Manuthor force-pushed the feat/key-rotation-notifications branch from 5f074fa to 4b5820b Compare May 29, 2026 14:03
@Manuthor Manuthor force-pushed the feat/key-rotation-scheduler branch from f27b7e5 to 43b5cdb Compare June 1, 2026 06:32
@Manuthor Manuthor changed the title [auto-rotation feature] feat: add notifications infrastructure for key auto-rotation events [auto-rotation feature] PR 3 — Notification system (SMTP email) Jun 7, 2026
@Manuthor Manuthor changed the title [auto-rotation feature] PR 3 — Notification system (SMTP email) [auto-rotation feature] PR 4 - Notification system (SMTP email) Jun 10, 2026
@Manuthor Manuthor force-pushed the feat/key-rotation-scheduler branch 3 times, most recently from cf711aa to bea7e61 Compare June 14, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant