344 lines
8.9 KiB
Rust
344 lines
8.9 KiB
Rust
|
|
//! KMS Module Facade
|
||
|
|
//!
|
||
|
|
//! Provides a stable, trait-based interface for the KMS module,
|
||
|
|
//! reducing coupling by hiding implementation details.
|
||
|
|
|
||
|
|
use async_trait::async_trait;
|
||
|
|
|
||
|
|
use crate::kms::error::{KmsError, Result};
|
||
|
|
use crate::kms::types::{KeyData, KeyType, ProviderCredentials};
|
||
|
|
|
||
|
|
/// Stable facade trait for Key Management Service operations
|
||
|
|
///
|
||
|
|
/// This trait defines the public contract for KMS operations,
|
||
|
|
/// allowing implementations to change without affecting consumers.
|
||
|
|
///
|
||
|
|
/// # Design Goals
|
||
|
|
///
|
||
|
|
/// - **Stable Interface**: Public API remains constant across refactorings
|
||
|
|
/// - **Implementation Hiding**: Internal details are not exposed
|
||
|
|
/// - **Testability**: Easy to mock for testing
|
||
|
|
/// - **Extensibility**: New features added without breaking changes
|
||
|
|
///
|
||
|
|
/// # Usage
|
||
|
|
///
|
||
|
|
/// ```rust,no_run
|
||
|
|
/// use control_center::kms::{KmsService, KmsConfig};
|
||
|
|
/// use std::sync::Arc;
|
||
|
|
///
|
||
|
|
/// async fn example(kms: Arc<dyn KmsService>) -> anyhow::Result<()> {
|
||
|
|
/// // Use the trait, not the concrete type
|
||
|
|
/// let key = kms.generate_key(/* params */).await?;
|
||
|
|
/// println!("Generated key: {}", key.key_id);
|
||
|
|
/// Ok(())
|
||
|
|
/// }
|
||
|
|
/// ```
|
||
|
|
#[async_trait]
|
||
|
|
pub trait KmsService: Send + Sync {
|
||
|
|
/// Initialize the KMS system
|
||
|
|
///
|
||
|
|
/// Performs one-time setup including backend initialization,
|
||
|
|
/// rotation scheduler startup, and credential manager configuration.
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Configuration` - Invalid configuration
|
||
|
|
/// - `Backend` - Backend initialization failed
|
||
|
|
/// - `Internal` - System initialization failed
|
||
|
|
async fn initialize(&mut self) -> Result<()>;
|
||
|
|
|
||
|
|
/// Get a key by ID
|
||
|
|
///
|
||
|
|
/// Retrieves key data from the configured backend.
|
||
|
|
/// Access is logged for audit purposes.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Unique identifier for the key
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Key data if found, None otherwise
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Backend` - Backend query failed
|
||
|
|
/// - `Audit` - Audit logging failed
|
||
|
|
async fn get_key(&self, key_id: &str) -> Result<Option<KeyData>>;
|
||
|
|
|
||
|
|
/// Store a new key
|
||
|
|
///
|
||
|
|
/// Persists key data to the configured backend.
|
||
|
|
/// Storage operation is logged for audit purposes.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key` - Key data to store
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// The stored key ID
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `KeyAlreadyExists` - Key with same ID already exists
|
||
|
|
/// - `Validation` - Invalid key data
|
||
|
|
/// - `Backend` - Backend storage failed
|
||
|
|
async fn store_key(&self, key: KeyData) -> Result<String>;
|
||
|
|
|
||
|
|
/// Delete a key by ID
|
||
|
|
///
|
||
|
|
/// Removes key from the backend. Deletion is permanent.
|
||
|
|
/// Operation is logged for audit purposes.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Unique identifier for the key
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// true if key was deleted, false if not found
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Backend` - Backend deletion failed
|
||
|
|
/// - `Audit` - Audit logging failed
|
||
|
|
async fn delete_key(&self, key_id: &str) -> Result<bool>;
|
||
|
|
|
||
|
|
/// Encrypt data with a key
|
||
|
|
///
|
||
|
|
/// Uses the specified key to encrypt plaintext data.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Key to use for encryption
|
||
|
|
/// * `plaintext` - Data to encrypt
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Encrypted ciphertext
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `KeyNotFound` - Specified key does not exist
|
||
|
|
/// - `Cryptographic` - Encryption operation failed
|
||
|
|
/// - `PermissionDenied` - Key does not allow encryption
|
||
|
|
async fn encrypt(&self, key_id: &str, plaintext: &[u8]) -> Result<Vec<u8>>;
|
||
|
|
|
||
|
|
/// Decrypt data with a key
|
||
|
|
///
|
||
|
|
/// Uses the specified key to decrypt ciphertext data.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Key to use for decryption
|
||
|
|
/// * `ciphertext` - Data to decrypt
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Decrypted plaintext
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `KeyNotFound` - Specified key does not exist
|
||
|
|
/// - `Cryptographic` - Decryption operation failed
|
||
|
|
/// - `PermissionDenied` - Key does not allow decryption
|
||
|
|
async fn decrypt(&self, key_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>>;
|
||
|
|
|
||
|
|
/// Generate a new encryption key
|
||
|
|
///
|
||
|
|
/// Creates a new key with the specified parameters and stores it.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_type` - Type of key to generate
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Generated key data
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Cryptographic` - Key generation failed
|
||
|
|
/// - `Backend` - Storage failed
|
||
|
|
async fn generate_key(&self, key_type: KeyType) -> Result<KeyData>;
|
||
|
|
|
||
|
|
/// Rotate a key
|
||
|
|
///
|
||
|
|
/// Generates a new version of an existing key.
|
||
|
|
/// Old version is marked as deprecated but retained.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Key to rotate
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// New key data
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `KeyNotFound` - Specified key does not exist
|
||
|
|
/// - `Rotation` - Rotation operation failed
|
||
|
|
async fn rotate_key(&self, key_id: &str) -> Result<KeyData>;
|
||
|
|
|
||
|
|
/// Get provider credentials
|
||
|
|
///
|
||
|
|
/// Retrieves stored credentials for a cloud provider.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `provider` - Provider name (e.g., "aws", "upcloud")
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Provider credentials if found
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Backend` - Credential retrieval failed
|
||
|
|
async fn get_provider_credentials(&self, provider: &str)
|
||
|
|
-> Result<Option<ProviderCredentials>>;
|
||
|
|
|
||
|
|
/// Store provider credentials
|
||
|
|
///
|
||
|
|
/// Securely stores credentials for a cloud provider.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `provider` - Provider name
|
||
|
|
/// * `credentials` - Provider credentials
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Backend` - Credential storage failed
|
||
|
|
/// - `Cryptographic` - Credential encryption failed
|
||
|
|
async fn store_provider_credentials(
|
||
|
|
&self,
|
||
|
|
provider: &str,
|
||
|
|
credentials: ProviderCredentials,
|
||
|
|
) -> Result<()>;
|
||
|
|
|
||
|
|
/// Shutdown the KMS system
|
||
|
|
///
|
||
|
|
/// Gracefully shuts down all KMS components including
|
||
|
|
/// rotation scheduler and backend connections.
|
||
|
|
///
|
||
|
|
/// # Errors
|
||
|
|
///
|
||
|
|
/// - `Backend` - Backend shutdown failed
|
||
|
|
async fn shutdown(&mut self) -> Result<()>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Extension trait for advanced KMS operations
|
||
|
|
///
|
||
|
|
/// Provides optional advanced functionality that not all implementations
|
||
|
|
/// may support. Check backend capabilities before using.
|
||
|
|
#[async_trait]
|
||
|
|
pub trait KmsServiceExt: KmsService {
|
||
|
|
/// Health check for KMS system
|
||
|
|
///
|
||
|
|
/// Returns detailed health status for all components.
|
||
|
|
async fn health_check(&self) -> Result<KmsHealthStatus>;
|
||
|
|
|
||
|
|
/// List all keys matching criteria
|
||
|
|
///
|
||
|
|
/// Returns keys filtered by optional parameters.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_type` - Filter by key type (None for all)
|
||
|
|
/// * `status` - Filter by status (None for all)
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Vector of matching key IDs
|
||
|
|
async fn list_keys(
|
||
|
|
&self,
|
||
|
|
key_type: Option<KeyType>,
|
||
|
|
status: Option<KeyStatus>,
|
||
|
|
) -> Result<Vec<String>>;
|
||
|
|
|
||
|
|
/// Get key statistics
|
||
|
|
///
|
||
|
|
/// Returns aggregate metrics about keys in the system.
|
||
|
|
async fn get_statistics(&self) -> Result<KmsStatistics>;
|
||
|
|
|
||
|
|
/// Export key for backup
|
||
|
|
///
|
||
|
|
/// Exports a key in encrypted form for backup purposes.
|
||
|
|
/// Requires export permission on the key.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `key_id` - Key to export
|
||
|
|
/// * `wrap_key_id` - Key to use for wrapping
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Wrapped key data
|
||
|
|
async fn export_key(&self, key_id: &str, wrap_key_id: &str) -> Result<Vec<u8>>;
|
||
|
|
|
||
|
|
/// Import a key from backup
|
||
|
|
///
|
||
|
|
/// Imports a previously exported key.
|
||
|
|
///
|
||
|
|
/// # Arguments
|
||
|
|
///
|
||
|
|
/// * `wrapped_key` - Encrypted key data
|
||
|
|
/// * `unwrap_key_id` - Key to use for unwrapping
|
||
|
|
///
|
||
|
|
/// # Returns
|
||
|
|
///
|
||
|
|
/// Imported key ID
|
||
|
|
async fn import_key(&self, wrapped_key: &[u8], unwrap_key_id: &str) -> Result<String>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// KMS health status
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct KmsHealthStatus {
|
||
|
|
pub backend: ComponentHealth,
|
||
|
|
pub rotation: ComponentHealth,
|
||
|
|
pub credentials: ComponentHealth,
|
||
|
|
pub overall: bool,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl KmsHealthStatus {
|
||
|
|
pub fn is_healthy(&self) -> bool {
|
||
|
|
self.overall
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Component health status
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct ComponentHealth {
|
||
|
|
pub healthy: bool,
|
||
|
|
pub message: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl ComponentHealth {
|
||
|
|
pub fn is_healthy(&self) -> bool {
|
||
|
|
self.healthy
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Key status enumeration (re-exported for facade)
|
||
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
|
|
pub enum KeyStatus {
|
||
|
|
Active,
|
||
|
|
Pending,
|
||
|
|
Deactivated,
|
||
|
|
Compromised,
|
||
|
|
Destroyed,
|
||
|
|
Archived,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// KMS statistics
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct KmsStatistics {
|
||
|
|
pub total_keys: usize,
|
||
|
|
pub active_keys: usize,
|
||
|
|
pub expired_keys: usize,
|
||
|
|
pub rotation_pending: usize,
|
||
|
|
}
|