Feat/platform key management#244
Merged
Merged
Conversation
added 2 commits
March 27, 2026 09:47
Implements hybrid ECDH-ES + AES-256-GCM payload encryption for
sensitive fields transmitted between API consumers and the platform.
## What's included
### Core crypto module (src/crypto/)
- envelope.rs — EncryptedEnvelope wire format, AES-256-GCM helpers,
session key generation, nonce/ciphertext decoding
- keys.rs — EC P-384 key pair management, ECDH-ES + AES-256-KW
session key unwrapping, KeyStore with versioning,
sensitive field catalogue, aes_kw_wrap/unwrap (RFC 3394)
- middleware.rs — Axum decryption middleware: detects envelopes, decrypts
fields, enforces grace-period / mandatory encryption,
zeroes session key after use, never logs plaintext
- metrics.rs — Prometheus counters: decryptions, failures, key version
usage, plaintext rejections
### API endpoints (src/api/crypto.rs)
- GET /api/crypto/public-key — returns current + transitional keys
- POST /api/crypto/test-decrypt — non-production integration test helper
### Database migration
- migrations/20260328200000_payload_encryption_keys.sql
Key version registry table (public key PEM only; private key in secrets manager)
### Tests
- src/crypto/tests.rs — unit tests: AES-GCM round-trip,
auth tag tamper rejection, key version validation, envelope parsing,
full ECDH-ES + AES-KW + AES-GCM round-trip, sensitive field catalogue
- tests/payload_encryption_test.rs — integration tests: encrypted field
decryption, multiple fields, key rotation (transitional key), retired
key rejection, plaintext rejection, grace period, tamper detection
### Module wiring fixes
- src/lib.rs: add pub mod crypto, remove duplicate pub mod recurring
- src/metrics/mod.rs: fix truncated request_anomaly_flags_total fn body
- src/middleware/mod.rs: remove duplicate replay_prevention + scope_middleware
## Security properties
- Private keys never stored in DB, repo, or logs
- Session key zeroed (Zeroizing) immediately after all field decryptions
- GCM auth tag verified on every field — tampered ciphertext rejected
- Retired key versions rejected with clear error code
- Plaintext sensitive fields rejected after grace period expires
- Decrypted values never appear in any log at any level
Unified lifecycle management for all cryptographic keys across the platform.
## Modules
### src/key_management/
- mod.rs — module root
- catalogue.rs — PlatformKey metadata model, KeyCatalogueRepository
(list, get, insert, update_status, mark_rotated, append_event,
events_for_key). Key material NEVER stored — metadata only.
- rotation.rs — KeyRotationScheduler: daily sweep identifies due keys,
initiates zero-downtime rotation with configurable grace periods
(JWT: 1 day, others: 7 days). KeyRotationWorker background task.
Helpers: days_until_rotation, is_in_grace_period.
- emergency.rs — EmergencyRevocationService: immediate revocation with no grace
period, generates replacement key, invalidates JWT tokens via
token_registry for JWT signing key revocations.
- reencryption.rs — ReencryptionService: creates per-table batch re-encryption jobs
when DB field encryption key is rotated. Old key only retired
after all jobs complete. Progress tracked in DB.
- escrow.rs — Shamir's Secret Sharing (GF(256) polynomial, no external crate).
split(secret, threshold, total) / reconstruct(shares, threshold).
- metrics.rs — Prometheus: rotations_initiated, rotation_failures,
grace_periods_expired, emergency_revocations, keys_by_status,
days_until_rotation, reencryption_progress_ratio.
### src/api/key_management.rs
- GET /api/admin/security/keys — paginated key catalogue
- GET /api/admin/security/keys/:key_id — key detail + full event history
- POST /api/admin/security/keys/:key_id/revoke — emergency revocation
### migrations/20260329000000_platform_key_management.sql
- platform_keys — key metadata catalogue (no key material)
- platform_key_events — immutable audit trail for all lifecycle events
- reencryption_jobs — per-table re-encryption progress tracking
## Rotation schedules
| Key type | Interval |
|---------------------|----------|
| JWT signing | 90 days |
| Payload encryption | 180 days |
| DB field encryption | 365 days |
| HMAC derivation | 90 days |
| Backup encryption | 365 days |
## Tests
- src/key_management/tests.rs — unit: rotation schedule, grace period,
key status transitions, Shamir SSS (6 cases), re-encryption batch logic
- tests/key_management_test.rs — integration: all key type schedules,
zero-downtime grace period, overdue detection, escrow 3-of-5 distribution
and recovery, batch processing, emergency revocation invariants,
key metadata serialization has no key material fields
## Module wiring
- src/lib.rs: pub mod key_management added
- src/metrics/mod.rs: key_management::metrics::register(r) added
- Cargo.toml: [[test]] key_management_test added
|
@Mac-5 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes #201