//! Configuration file encryption example. //! //! Demonstrates a practical use case: encrypting sensitive fields in //! configuration files using different backends. //! //! # Typical Workflow //! //! 1. Developer has plaintext config with secrets //! 2. Run encryption to hide sensitive values //! 3. Store encrypted config in version control //! 4. At runtime, decrypt using available backend //! 5. Different environments use different backends (Age for dev, KMS for prod) //! //! # Usage //! //! ```bash //! cargo run --example config_encryption --features age,sops //! ``` use encrypt::{decrypt, encrypt, BackendSpec}; #[derive(Debug, Clone)] struct AppConfig { name: String, db_host: String, db_password: String, api_key: String, debug: bool, } impl AppConfig { fn example() -> Self { Self { name: "MyApp".to_string(), db_host: "postgres.example.com".to_string(), db_password: "super-secret-postgres-pwd-123".to_string(), api_key: "sk-prod-1234567890abcdef".to_string(), debug: false, } } fn display_plaintext(&self) { println!("Configuration (PLAINTEXT):"); println!(" name: {}", self.name); println!(" db_host: {}", self.db_host); println!(" db_password: {}", self.db_password); println!(" api_key: {}", self.api_key); println!(" debug: {}\n", self.debug); } fn display_encrypted(&self, backend_name: &str) { println!("Configuration (ENCRYPTED with {}):", backend_name); println!(" name: {}", self.name); println!(" db_host: {}", self.db_host); println!(" db_password: [ENCRYPTED]"); println!(" api_key: [ENCRYPTED]"); println!(" debug: {}\n", self.debug); } } fn encrypt_config( config: &AppConfig, spec: &BackendSpec, ) -> Result<(String, String), Box> { let encrypted_password = encrypt(&config.db_password, spec)?; let encrypted_api_key = encrypt(&config.api_key, spec)?; Ok((encrypted_password, encrypted_api_key)) } fn decrypt_secrets( encrypted_password: &str, encrypted_api_key: &str, spec: &BackendSpec, ) -> Result<(String, String), Box> { let password = decrypt(encrypted_password, spec)?; let api_key = decrypt(encrypted_api_key, spec)?; Ok((password, api_key)) } fn main() -> Result<(), Box> { println!("=== Configuration Encryption Example ===\n"); let config = AppConfig::example(); // Step 1: Show plaintext config println!("Step 1: Original Configuration"); println!("================================"); config.display_plaintext(); // Step 2: Encrypt with Age backend println!("Step 2: Encrypt with Age Backend"); println!("================================="); let age_spec = BackendSpec::age_default(); match encrypt_config(&config, &age_spec) { Ok((encrypted_password, encrypted_api_key)) => { println!("✓ Encrypted successfully\n"); // Show config with encrypted values config.display_encrypted("Age"); // Step 3: Simulate storing in version control println!("Step 3: Store in Version Control"); println!("================================="); println!( "Encrypted password (first 60 chars): {}...", &encrypted_password[..60.min(encrypted_password.len())] ); println!( "Encrypted API key (first 60 chars): {}...\n", &encrypted_api_key[..60.min(encrypted_api_key.len())] ); // Step 4: Decrypt for runtime use println!("Step 4: Decrypt at Runtime"); println!("=========================="); match decrypt_secrets(&encrypted_password, &encrypted_api_key, &age_spec) { Ok((decrypted_password, decrypted_api_key)) => { println!("✓ Decrypted successfully\n"); // Verify values match if decrypted_password == config.db_password && decrypted_api_key == config.api_key { println!("✓ All secrets recovered correctly!"); println!(" - Database password matches"); println!(" - API key matches"); } else { println!("✗ Secret mismatch!"); return Err("Decryption verification failed".into()); } } Err(e) => { println!("✗ Decryption failed: {}\n", e); return Err(e); } } } Err(e) => { println!("✗ Encryption failed: {}\n", e); println!("Ensure Age key exists: age-keygen -o ~/.age/key.txt"); return Err(e); } } // Step 5: Show multi-environment example println!("\nStep 5: Multi-Environment Example"); println!("=================================="); println!("\nDevelopment (Age - local):"); let dev_spec = BackendSpec::age_default(); println!(" Backend: {}", dev_spec.backend_name()); println!(" Location: ~/.age/key.txt"); println!(" Use case: Local development, no KMS needed\n"); println!("Staging (SOPS - AWS KMS):"); let staging_spec = BackendSpec::sops(); println!(" Backend: {}", staging_spec.backend_name()); println!(" Location: .sops.yaml → AWS KMS"); println!(" Use case: Team environment with key management\n"); println!("Production (SecretumVault - post-quantum):"); let prod_spec = BackendSpec::secretumvault("https://vault.prod:8200", "token", "app-key"); println!(" Backend: {}", prod_spec.backend_name()); println!(" Location: SecretumVault HTTP API"); println!(" Use case: Enterprise with post-quantum crypto requirements\n"); println!("Configuration Management Best Practices:"); println!(" 1. Never commit plaintext secrets to Git"); println!(" 2. Use different backends per environment"); println!(" 3. Rotate keys regularly"); println!(" 4. Log who accessed which secrets"); println!(" 5. Use encryption context for audit trails"); println!(" 6. Implement secret versioning"); Ok(()) }