# SecretumVault - Complete Post-Quantum Secrets Management System **Version:** 3.0 **Date:** 2025-12-21 **Author:** Jesús Pérez (Kit Digital / Rust Las Palmas) **Project Name:** `secretumvault` or `svault` ## Executive Summary **SecretumVault** es un sistema completo de gestión de secretos con: - ✅ **Post-Quantum Crypto** desde el diseño (no retrofitted) - ✅ **Secrets Management** completo (KV, dynamic, transit) - ✅ **Cedar Policies** (modern authorization, no ACL legacy) - ✅ **Multi-Backend Crypto** (aws-lc-rs, RustCrypto, Tongsuo) - ✅ **Encryption as a Service** (EaaS) - ✅ **Storage Flexible** (SurrealDB, filesystem, etcd) - ✅ **API Compatible** con HashiCorp Vault (migration path) - ✅ **Rust Native** (memory safe, high performance) **NO es**: - ❌ NO tiene auth complejo (OIDC, LDAP) - solo lo esencial - ❌ NO tiene ACL legacy - usa Cedar policies - ❌ NO compite con Enterprise Vault features **Es ideal para**: - ✅ Kit Digital projects (PYMES españolas) - ✅ Aplicaciones que necesitan PQC ahora - ✅ Infraestructura moderna (Kubernetes, SurrealDB) - ✅ Compliance NIS2 + post-quantum readiness --- ## Table of Contents 1. [Core Concepts](#core-concepts) 2. [Architecture](#architecture) 3. [Secrets Engines](#secrets-engines) 4. [Authorization with Cedar](#authorization-with-cedar) 5. [Crypto Backends](#crypto-backends) 6. [Storage Backends](#storage-backends) 7. [API Design](#api-design) 8. [Deployment Modes](#deployment-modes) 9. [Integration Examples](#integration-examples) 10. [Implementation Roadmap](#implementation-roadmap) --- ## Core Concepts ### What is SecretumVault? ``` SecretumVault = Secrets Manager + Encryption Service + Key Management + Cedar Policies + Post-Quantum Crypto ``` ### Key Features 1. **Secrets Management** - Key/Value secrets (static) - Dynamic secrets (database, cloud) - Transit encryption (EaaS) - SSH/TLS certificate generation 2. **Post-Quantum Ready** - ML-KEM for key encapsulation - ML-DSA for signatures - Hybrid modes (classical + PQC) - Future-proof key rotation 3. **Modern Authorization** - Cedar policy language (AWS open-source) - Attribute-based access control (ABAC) - No legacy ACL complexity - Policy-as-Code 4. **High Performance** - Rust native (no GC pauses) - Async/await throughout - Optimized crypto backends - Efficient storage --- ## Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ CLIENT LAYER │ ├─────────────────────────────────────────────────────────────────┤ │ REST API │ CLI │ Rust SDK │ Language SDKs (future) │ └──────┬──────────────────────────────────────────────────────────┘ │ ┌──────▼──────────────────────────────────────────────────────────┐ │ QUANTUMVAULT CORE │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │ │ Request │ │ Auth/Policy │ │ Secrets Router │ │ │ │ Handler │→ │ Engine │→ │ (Path-based) │ │ │ └─────────────┘ └──────────────┘ └──────────────────────┘ │ │ │ │ │ │ ↓ ↓ │ │ ┌──────────────────┐ ┌────────────────────┐ │ │ │ Cedar Policies │ │ Secrets Engines │ │ │ │ (Authorization) │ │ (KV, Transit, │ │ │ └──────────────────┘ │ Dynamic, PKI) │ │ │ └────────────────────┘ │ │ │ │ └──────────────────────────────────────────────┼──────────────────┘ │ ┌───────────────────────────────────────┼───────────────┐ │ │ │ ┌──────▼────────┐ ┌──────────────▼──────┐ ┌▼──────────────┐ │ │ Crypto Layer │ │ Storage Layer │ │ Seal/Unseal │ │ ├───────────────┤ ├─────────────────────┤ ├───────────────┤ │ │ • aws-lc-rs │ │ • SurrealDB │ │ • Master Key │ │ │ • RustCrypto │ │ • Filesystem │ │ • Shamir SSS │ │ │ • Tongsuo │ │ • etcd/Consul │ │ • Auto-unseal │ │ │ • OpenSSL │ │ • PostgreSQL │ │ (KMS) │ │ └───────────────┘ └─────────────────────┘ └───────────────┘ │ │ └────────────────────────────────────────────────────────────────┘ ``` --- ## Secrets Engines SecretumVault soporta múltiples "engines" montados en paths: ### 1. KV Engine (Key-Value Secrets) **Path**: `secret/` ```rust // API POST /v1/secret/data/myapp/database # Write secret GET /v1/secret/data/myapp/database # Read secret DELETE /v1/secret/data/myapp/database # Delete secret GET /v1/secret/metadata/myapp/database # Get metadata ``` **Implementación**: ```rust pub struct KVEngine { storage: Arc, versioned: bool, // KV v1 o v2 } #[derive(Serialize, Deserialize)] pub struct SecretData { pub data: HashMap, pub metadata: SecretMetadata, } #[derive(Serialize, Deserialize)] pub struct SecretMetadata { pub version: u64, pub created_at: DateTime, pub updated_at: DateTime, pub deleted: bool, pub destroyed: bool, } impl SecretsEngine for KVEngine { async fn write( &self, path: &str, data: HashMap, ) -> Result { let mut metadata = SecretMetadata { version: self.get_next_version(path).await?, created_at: Utc::now(), updated_at: Utc::now(), deleted: false, destroyed: false, }; let secret = SecretData { data, metadata: metadata.clone() }; // Encrypt data before storing let encrypted = self.encrypt_secret(&secret).await?; self.storage.store_secret(path, &encrypted).await?; Ok(metadata) } async fn read(&self, path: &str) -> Result { let encrypted = self.storage.get_secret(path).await?; let secret = self.decrypt_secret(&encrypted).await?; if secret.metadata.deleted { return Err(Error::SecretDeleted); } Ok(secret) } } ``` ### 2. Transit Engine (Encryption as a Service) **Path**: `transit/` Permite a aplicaciones cifrar/descifrar datos sin manejar claves directamente. ```rust // API POST /v1/transit/encrypt/my-key # Encrypt data POST /v1/transit/decrypt/my-key # Decrypt data POST /v1/transit/sign/my-key # Sign data (PQC) POST /v1/transit/verify/my-key # Verify signature POST /v1/transit/rewrap/my-key # Re-encrypt with new key version ``` **Implementación**: ```rust pub struct TransitEngine { crypto: Arc, key_manager: Arc, } #[derive(Deserialize)] pub struct EncryptRequest { pub plaintext: String, // Base64 pub context: Option, // Additional authenticated data } #[derive(Serialize)] pub struct EncryptResponse { pub ciphertext: String, // vault:v1:base64ciphertext } impl SecretsEngine for TransitEngine { async fn handle_encrypt( &self, key_name: &str, req: EncryptRequest, ) -> Result { // 1. Decode plaintext let plaintext = base64::decode(&req.plaintext)?; // 2. Get encryption key (latest version) let key = self.key_manager.get_key(key_name).await?; // 3. Encrypt with crypto backend let ciphertext = match key.algorithm { KeyAlgorithm::Aes256Gcm => { self.crypto.encrypt_symmetric(&key.key_data, &plaintext, SymmetricAlgorithm::Aes256Gcm)? } KeyAlgorithm::ChaCha20Poly1305 => { self.crypto.encrypt_symmetric(&key.key_data, &plaintext, SymmetricAlgorithm::ChaCha20Poly1305)? } _ => return Err(Error::InvalidAlgorithm), }; // 4. Format response (Vault-compatible) let encoded = format!( "vault:v{}:{}", key.version, base64::encode(&ciphertext) ); Ok(EncryptResponse { ciphertext: encoded, }) } async fn handle_sign( &self, key_name: &str, data: &[u8], ) -> Result { let key = self.key_manager.get_key(key_name).await?; // Firmar con PQC (ML-DSA) let signature = self.crypto.sign(&key.private_key, data)?; Ok(format!( "vault:v{}:{}", key.version, base64::encode(&signature) )) } } ``` ### 3. PKI Engine (Certificate Authority) **Path**: `pki/` Genera certificados X.509 (RSA/ECDSA tradicional + PQC experimental). ```rust pub struct PKIEngine { crypto: Arc, ca_bundle: Option, } #[derive(Deserialize)] pub struct IssueCertRequest { pub common_name: String, pub alt_names: Vec, pub ttl: String, // e.g., "720h" pub algorithm: CertAlgorithm, // RSA2048, ECDSA256, ML-DSA-65 } impl SecretsEngine for PKIEngine { async fn issue_cert(&self, req: IssueCertRequest) -> Result { // 1. Generate keypair let keypair = self.crypto.generate_keypair( req.algorithm.to_key_algorithm() )?; // 2. Create CSR let csr = create_csr(&keypair, &req.common_name, &req.alt_names)?; // 3. Sign with CA let cert = self.ca_bundle .as_ref() .ok_or(Error::NoCAConfigured)? .sign_csr(&csr, parse_duration(&req.ttl)?)?; Ok(cert) } } ``` ### 4. Dynamic Secrets Engine **Path**: `database/`, `aws/`, `gcp/` Genera credenciales dinámicas on-demand. ```rust pub struct DatabaseEngine { connections: HashMap, } #[derive(Deserialize)] pub struct GetCredsRequest { pub role: String, // e.g., "readonly", "admin" } #[derive(Serialize)] pub struct DatabaseCreds { pub username: String, pub password: String, pub lease_duration: u64, // seconds } impl SecretsEngine for DatabaseEngine { async fn get_credentials( &self, role: &str, ) -> Result { let role_config = self.get_role_config(role).await?; // Generate random username/password let username = format!("v-{}-{}", role, generate_id()); let password = generate_secure_password(32); // Create user in database let db = self.connections.get(&role_config.connection) .ok_or(Error::ConnectionNotFound)?; db.execute(&format!( "CREATE USER '{}' IDENTIFIED BY '{}';", username, password )).await?; // Grant permissions for stmt in &role_config.creation_statements { db.execute(stmt).await?; } // Schedule revocation self.schedule_revocation(&username, role_config.ttl).await?; Ok(DatabaseCreds { username, password, lease_duration: role_config.ttl.as_secs(), }) } } ``` --- ## Authorization with Cedar En lugar de ACL tradicional, usamos **Cedar** (AWS open-source policy language). ### Cedar Overview Cedar es: - ✅ Expresivo y declarativo - ✅ Verificable formalmente - ✅ Policy-as-Code - ✅ Usado por AWS (AVP) ### Policy Example **Archivo**: `policies/allow-read-secrets.cedar` ```cedar // Permitir a developers leer secrets de su proyecto permit( principal in Group::"developers", action == Action::"read", resource in Project::"kit-digital" ) when { context.environment == "development" || context.environment == "staging" }; // Permitir a CI/CD leer solo secrets de deployment permit( principal == ServiceAccount::"github-actions", action in [Action::"read", Action::"encrypt"], resource in Path::"secret/deployments/*" ) when { context.ip_address in [ "192.30.252.0/22", // GitHub Actions IPs "185.199.108.0/22" ] }; // Permitir a admins todo permit( principal in Group::"admins", action, resource ); // Denegar escritura a production desde dev environments forbid( principal, action in [Action::"write", Action::"delete"], resource in Path::"secret/production/*" ) when { context.environment != "production" }; ``` ### Cedar Integration **Archivo**: `src/auth/cedar.rs` ```rust use cedar_policy::{Authorizer, Context, Entities, PolicySet, Request}; pub struct CedarAuthz { authorizer: Authorizer, policies: PolicySet, entities: Entities, } impl CedarAuthz { pub fn from_files(policy_dir: &str) -> Result { let policies = load_policies_from_dir(policy_dir)?; let entities = load_entities()?; // Groups, users, etc. Ok(Self { authorizer: Authorizer::new(), policies, entities, }) } pub fn is_authorized( &self, principal: &str, action: &str, resource: &str, context: RequestContext, ) -> Result { let request = Request::new( Some(principal.parse()?), Some(action.parse()?), Some(resource.parse()?), Context::from_json_value(serde_json::to_value(context)?)?, )?; let response = self.authorizer.is_authorized( &request, &self.policies, &self.entities, ); Ok(response.decision() == cedar_policy::Decision::Allow) } } #[derive(Serialize)] pub struct RequestContext { pub environment: String, pub ip_address: String, pub timestamp: i64, pub mfa_verified: bool, } // Integración con Vault impl Vault { async fn handle_request( &self, req: VaultRequest, auth_token: &str, ) -> Result { // 1. Validate token let principal = self.auth.validate_token(auth_token).await?; // 2. Build context let context = RequestContext { environment: req.headers.get("X-Vault-Environment") .unwrap_or("unknown").to_string(), ip_address: req.remote_addr.to_string(), timestamp: Utc::now().timestamp(), mfa_verified: self.auth.is_mfa_verified(&principal).await?, }; // 3. Authorize with Cedar let authorized = self.cedar.is_authorized( &principal.id, &req.operation, // "read", "write", "delete" &req.path, // "secret/production/db" context, )?; if !authorized { return Err(Error::PermissionDenied); } // 4. Route to appropriate engine self.route_request(req).await } } ``` ### Entities Definition **Archivo**: `entities.json` ```json [ { "uid": {"type": "User", "id": "alice"}, "attrs": { "email": "alice@example.com", "groups": ["developers", "admins"] }, "parents": [ {"type": "Group", "id": "developers"}, {"type": "Group", "id": "admins"} ] }, { "uid": {"type": "ServiceAccount", "id": "github-actions"}, "attrs": { "type": "ci-cd", "trusted": true } }, { "uid": {"type": "Group", "id": "developers"}, "attrs": {}, "parents": [] } ] ``` --- ## Crypto Backends ### Backend Interface (ya definido anteriormente) ```rust pub trait CryptoBackend: Debug + Send + Sync { fn backend_type(&self) -> BackendType; // Asymmetric fn generate_keypair(&self, algorithm: KeyAlgorithm) -> Result; fn sign(&self, key: &PrivateKey, data: &[u8]) -> Result>; fn verify(&self, key: &PublicKey, data: &[u8], sig: &[u8]) -> Result; // Symmetric fn encrypt_symmetric(&self, key: &[u8], data: &[u8], alg: SymmetricAlgorithm) -> Result>; fn decrypt_symmetric(&self, key: &[u8], data: &[u8], alg: SymmetricAlgorithm) -> Result>; // KEM (for PQC) fn kem_encapsulate(&self, key: &PublicKey) -> Result<(Vec, Vec)>; fn kem_decapsulate(&self, key: &PrivateKey, ct: &[u8]) -> Result>; // Random fn random_bytes(&self, len: usize) -> Result>; } ``` ### Hybrid Crypto Mode Para defense-in-depth, soportar hybrid: ```rust pub struct HybridBackend { classical: Arc, // OpenSSL/aws-lc (RSA/ECDSA) pqc: Arc, // aws-lc-rs (ML-KEM/ML-DSA) } impl CryptoBackend for HybridBackend { fn kem_encapsulate(&self, key: &PublicKey) -> Result<(Vec, Vec)> { // Encapsulate with both let (ct_classical, ss_classical) = self.classical.kem_encapsulate(key)?; let (ct_pqc, ss_pqc) = self.pqc.kem_encapsulate(key)?; // Combine ciphertexts let combined_ct = [ct_classical, ct_pqc].concat(); // Derive shared secret from both using KDF let combined_ss = kdf_combine(&ss_classical, &ss_pqc)?; Ok((combined_ct, combined_ss)) } } ``` --- ## Storage Backends ### Storage Trait ```rust #[async_trait] pub trait StorageBackend: Debug + Send + Sync { // Secrets async fn store_secret(&self, path: &str, data: &EncryptedData) -> Result<()>; async fn get_secret(&self, path: &str) -> Result; async fn delete_secret(&self, path: &str) -> Result<()>; async fn list_secrets(&self, prefix: &str) -> Result>; // Keys async fn store_key(&self, key: &StoredKey) -> Result<()>; async fn get_key(&self, key_id: &str) -> Result; // Policies async fn store_policy(&self, name: &str, policy: &str) -> Result<()>; async fn get_policy(&self, name: &str) -> Result; async fn list_policies(&self) -> Result>; // Leases (for dynamic secrets) async fn store_lease(&self, lease: &Lease) -> Result<()>; async fn get_lease(&self, lease_id: &str) -> Result; async fn delete_lease(&self, lease_id: &str) -> Result<()>; async fn list_expiring_leases(&self, before: DateTime) -> Result>; } ``` ### SurrealDB Implementation ```rust pub struct SurrealDBBackend { db: Surreal, } #[async_trait] impl StorageBackend for SurrealDBBackend { async fn store_secret(&self, path: &str, data: &EncryptedData) -> Result<()> { let record = SecretRecord { path: path.to_string(), data: data.clone(), created_at: Utc::now(), updated_at: Utc::now(), }; let _: Option = self.db .create(("secrets", path)) .content(record) .await?; Ok(()) } async fn list_expiring_leases(&self, before: DateTime) -> Result> { let leases: Vec = self.db .query("SELECT * FROM leases WHERE expires_at <= $before") .bind(("before", before)) .await? .take(0)?; Ok(leases) } } ``` --- ## API Design ### Vault-Compatible REST API ```rust // Core paths GET /v1/sys/health // Health check POST /v1/sys/init // Initialize vault POST /v1/sys/unseal // Unseal vault POST /v1/sys/seal // Seal vault GET /v1/sys/seal-status // Get seal status // Auth POST /v1/auth/token/create // Create token POST /v1/auth/token/revoke // Revoke token POST /v1/auth/token/lookup // Lookup token // Secrets (KV) GET /v1/secret/data/:path // Read secret POST /v1/secret/data/:path // Write secret DELETE /v1/secret/data/:path // Delete secret GET /v1/secret/metadata/:path // Get metadata LIST /v1/secret/metadata/:path // List secrets // Transit (EaaS) POST /v1/transit/encrypt/:key // Encrypt data POST /v1/transit/decrypt/:key // Decrypt data POST /v1/transit/sign/:key // Sign data (PQC) POST /v1/transit/verify/:key // Verify signature POST /v1/transit/keys/:key // Create key POST /v1/transit/keys/:key/rotate // Rotate key // PKI POST /v1/pki/root/generate // Generate root CA POST /v1/pki/issue/:role // Issue certificate POST /v1/pki/revoke // Revoke certificate // Database (Dynamic) GET /v1/database/creds/:role // Get dynamic creds POST /v1/database/config/:name // Configure connection // Policies (Cedar) GET /v1/sys/policies // List policies GET /v1/sys/policy/:name // Read policy PUT /v1/sys/policy/:name // Write policy DELETE /v1/sys/policy/:name // Delete policy ``` ### Request/Response Format ```rust #[derive(Serialize, Deserialize)] pub struct VaultRequest { pub path: String, pub operation: Operation, // Read, Write, Delete, List pub data: Option, pub headers: HashMap, } #[derive(Serialize, Deserialize)] pub struct VaultResponse { pub request_id: String, pub lease_id: Option, pub renewable: bool, pub lease_duration: u64, pub data: Option, pub warnings: Vec, pub auth: Option, } ``` --- ## Deployment Modes ### 1. Standalone Server ```bash # Start server svault server --config svault.toml # Initialize svault operator init # Unseal svault operator unseal ``` ### 2. Kubernetes Deployment ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: secretumvault spec: serviceName: secretumvault replicas: 3 selector: matchLabels: app: secretumvault template: metadata: labels: app: secretumvault spec: containers: - name: vault image: secretumvault:latest ports: - containerPort: 8200 name: api env: - name: QVAULT_BACKEND value: "aws-lc" - name: QVAULT_STORAGE value: "surrealdb" volumeMounts: - name: config mountPath: /etc/secretumvault - name: data mountPath: /var/secretumvault volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi ``` ### 3. Library Mode (Embedded) ```rust // En tu aplicación use secretumvault::{Vault, VaultConfig}; #[tokio::main] async fn main() -> Result<()> { let config = VaultConfig::builder() .crypto_backend(BackendType::AwsLc) .storage_backend(StorageType::SurrealDB) .build()?; let vault = Vault::new(config).await?; // Usar vault embebido vault.write("secret/myapp/db", json!({ "username": "admin", "password": "secret123" })).await?; Ok(()) } ``` --- ## Integration Examples ### 1. Con RustyVault (como Backend) SecretumVault puede servir como crypto backend de RustyVault: ```rust // RustyVault usa SecretumVault para crypto use secretumvault::CryptoService; pub struct RustyVaultWithPQC { secrets: RustyVaultCore, crypto: Arc, // SecretumVault crypto } impl RustyVaultWithPQC { async fn sign_certificate(&self, csr: &[u8]) -> Result> { // Usar SecretumVault para firmar con ML-DSA self.crypto.sign("ca-key", csr).await } } ``` ### 2. Con provctl (Orchestration) ```rust use secretumvault::Vault; async fn provision_secure_machine(machine_id: &str) -> Result<()> { let vault = Vault::connect("https://vault.internal:8200").await?; // Get dynamic SSH credentials let ssh_creds = vault.read(&format!("ssh/creds/{}", machine_id)).await?; // Encrypt machine config let encrypted_config = vault.transit_encrypt( "machine-config-key", &machine_config.as_bytes() ).await?; // Deploy deploy_machine(machine_id, &ssh_creds, &encrypted_config).await?; Ok(()) } ``` ### 3. Con Nushell Scripts ```nu # vault-ops.nu export def get-db-creds [role: string] { let response = ( http get http://vault:8200/v1/database/creds/$role -H [X-Vault-Token $env.VAULT_TOKEN] ) { username: $response.data.username, password: $response.data.password, expires: ($response.lease_duration | into datetime) } } export def encrypt-file [file: string, key: string] { let plaintext = (open $file | encode base64) let response = ( http post http://vault:8200/v1/transit/encrypt/$key { plaintext: $plaintext } -H [X-Vault-Token $env.VAULT_TOKEN] ) $response.data.ciphertext | save $"($file).encrypted" } # Uso get-db-creds "readonly" | save db-creds.json encrypt-file "sensitive.txt" "app-key" ``` ### 4. Con Nickel Config ```nickel # vault-bootstrap.ncl let Vault = { server = "https://vault.internal:8200", policies = { developers = m%" permit( principal in Group::"developers", action == Action::"read", resource in Path::"secret/dev/*" ); "%, ci_cd = m%" permit( principal == ServiceAccount::"github-actions", action in [Action::"read", Action::"encrypt"], resource in Path::"secret/deployments/*" ); "%, }, secrets = { database = { connection = "postgresql://vault-db:5432/app", roles = { readonly = { creation_statements = [ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" ], ttl = "1h" }, admin = { creation_statements = [ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}' SUPERUSER;" ], ttl = "15m" } } } } } { vault = Vault } ``` --- ## Implementation Roadmap ### Phase 1: Foundation (Week 1-3) **Week 1**: Core Architecture - [ ] Project structure - [ ] Storage trait + filesystem implementation - [ ] Basic crypto backend (OpenSSL) - [ ] Seal/Unseal mechanism with Shamir **Week 2**: KV Engine - [ ] KV secrets engine (v2 with versioning) - [ ] Encryption at rest - [ ] API handlers for KV - [ ] CLI: read/write/delete **Week 3**: Auth & Cedar - [ ] Token-based authentication - [ ] Cedar policy integration - [ ] Policy evaluation - [ ] Basic ACL tests ### Phase 2: Crypto Engines (Week 4-6) **Week 4**: Transit Engine - [ ] Encrypt/decrypt endpoints - [ ] Key rotation - [ ] Multiple algorithm support - [ ] Rewrap functionality **Week 5**: PQC Integration - [ ] aws-lc-rs backend - [ ] ML-KEM implementation - [ ] ML-DSA signatures - [ ] Hybrid mode (classical + PQC) **Week 6**: PKI Engine - [ ] Root CA generation - [ ] Certificate issuance (RSA/ECDSA) - [ ] CRL/OCSP support - [ ] PQC certificates (experimental) ### Phase 3: Dynamic Secrets (Week 7-8) **Week 7**: Database Engine - [ ] PostgreSQL support - [ ] MySQL support - [ ] Lease management - [ ] Automatic revocation **Week 8**: Storage Backends - [ ] SurrealDB implementation - [ ] etcd/Consul support - [ ] Migration tools ### Phase 4: Production Ready (Week 9-10) **Week 9**: High Availability - [ ] Leader election - [ ] Replication - [ ] Auto-unseal with KMS - [ ] Performance optimizations **Week 10**: Polish & Docs - [ ] API documentation (OpenAPI) - [ ] Deployment guides - [ ] Security audit - [ ] Benchmarks --- ## Configuration Example **Archivo**: `svault.toml` ```toml [vault] # Crypto backend crypto_backend = "aws-lc" # aws-lc | rustcrypto | tongsuo | openssl # Storage backend storage_backend = "surrealdb" # surrealdb | filesystem | etcd | consul [server] address = "0.0.0.0:8200" tls_cert = "/etc/svault/tls/cert.pem" tls_key = "/etc/svault/tls/key.pem" # Mutual TLS (opcional) tls_client_ca = "/etc/svault/tls/ca.pem" [storage.surrealdb] endpoint = "ws://localhost:8000" namespace = "vault" database = "production" username = "vault" password = "${SURREAL_PASSWORD}" [storage.filesystem] path = "/var/svault/data" [seal] type = "shamir" # shamir | auto | transit shares = 5 threshold = 3 # Auto-unseal con KMS (opcional) [seal.auto] type = "aws-kms" # aws-kms | gcp-kms | azure-kv key_id = "arn:aws:kms:..." [auth.cedar] policies_dir = "/etc/svault/policies" entities_file = "/etc/svault/entities.json" [engines] # Secrets engines montados kv = { path = "secret/", versioned = true } transit = { path = "transit/" } pki = { path = "pki/" } database = { path = "database/" } [logging] level = "info" format = "json" output = "/var/log/svault/vault.log" [telemetry] prometheus_port = 9090 ``` --- ## Project Structure ``` secretumvault/ ├── Cargo.toml ├── README.md ├── config/ │ └── svault.toml.example │ ├── src/ │ ├── lib.rs │ ├── main.rs # Server binary │ │ │ ├── core/ │ │ ├── mod.rs │ │ ├── vault.rs # Main Vault struct │ │ ├── seal.rs # Seal/Unseal logic │ │ └── router.rs # Request routing │ │ │ ├── engines/ │ │ ├── mod.rs │ │ ├── kv.rs # KV engine │ │ ├── transit.rs # Transit engine │ │ ├── pki.rs # PKI engine │ │ └── database.rs # Dynamic secrets │ │ │ ├── auth/ │ │ ├── mod.rs │ │ ├── token.rs # Token auth │ │ └── cedar.rs # Cedar integration │ │ │ ├── crypto/ │ │ ├── mod.rs │ │ ├── backend.rs # Trait │ │ ├── aws_lc.rs │ │ ├── rustcrypto.rs │ │ └── tongsuo.rs │ │ │ ├── storage/ │ │ ├── mod.rs │ │ ├── filesystem.rs │ │ ├── surrealdb.rs │ │ ├── etcd.rs │ │ └── consul.rs │ │ │ ├── api/ │ │ ├── mod.rs │ │ ├── server.rs │ │ └── handlers/ │ │ ├── sys.rs │ │ ├── secret.rs │ │ ├── transit.rs │ │ └── pki.rs │ │ │ ├── shamir/ │ │ └── mod.rs │ │ │ └── error.rs │ ├── bin/ │ └── svault.rs # CLI tool │ ├── policies/ │ ├── default.cedar │ ├── developers.cedar │ └── ci-cd.cedar │ ├── scripts/ │ ├── vault-ops.nu # Nushell helpers │ └── init-vault.sh │ ├── configs/ │ ├── vault-config.ncl │ └── bootstrap.ncl │ └── tests/ ├── integration/ ├── engines/ └── auth/ ``` --- ## Cargo.toml ```toml [package] name = "secretumvault" version = "0.1.0" edition = "2021" authors = ["Jesús Pérez "] description = "Post-quantum ready secrets management system" license = "Apache-2.0" [features] default = ["aws-lc", "filesystem", "server"] # Crypto backends aws-lc = ["aws-lc-rs"] rustcrypto = ["ml-kem", "ml-dsa", "slh-dsa"] tongsuo = ["dep:tongsuo"] openssl = ["dep:openssl"] # Storage backends filesystem = [] surrealdb-storage = ["surrealdb"] etcd-storage = ["etcd-client"] consul-storage = ["consulrs"] # Components server = ["axum", "tower-http"] cli = ["clap"] cedar = ["cedar-policy"] [dependencies] # Core tokio = { version = "1.35", features = ["full"] } async-trait = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" toml = "0.8" thiserror = "1.0" anyhow = "1.0" chrono = { version = "0.4", features = ["serde"] } tracing = "0.1" tracing-subscriber = "0.3" # Crypto aws-lc-rs = { version = "1.9", features = ["unstable"], optional = true } ml-kem = { version = "0.2", optional = true } ml-dsa = { version = "0.2", optional = true } slh-dsa = { version = "0.2", optional = true } openssl = { version = "0.10", optional = true } tongsuo = { version = "0.3", optional = true } # Shamir Secret Sharing sharks = "0.5" # Cedar policies cedar-policy = { version = "3.0", optional = true } # Storage surrealdb = { version = "1.5", optional = true } etcd-client = { version = "0.13", optional = true } consulrs = { version = "0.1", optional = true } # Server axum = { version = "0.7", optional = true, features = ["macros"] } tower-http = { version = "0.5", optional = true, features = ["cors", "trace"] } # CLI clap = { version = "4.5", optional = true, features = ["derive"] } # Utilities uuid = { version = "1.6", features = ["v4", "serde"] } base64 = "0.21" hex = "0.4" [dev-dependencies] tempfile = "3.8" wiremock = "0.5" [[bin]] name = "svault" path = "src/main.rs" [[bin]] name = "svault-cli" path = "bin/svault.rs" required-features = ["cli"] ``` --- ## ¿Por qué SecretumVault vs. Solo Crypto Service? | Feature | Crypto Service Solo | SecretumVault Completo | |---|---|---| | Secrets Management | ❌ | ✅ KV + Dynamic | | Encryption as a Service | ⚠️ Básico | ✅ Transit engine completo | | Authorization | ❌ | ✅ Cedar policies | | PKI/Certificates | ❌ | ✅ Full CA | | Dynamic Secrets | ❌ | ✅ Database, cloud | | Lease Management | ❌ | ✅ Auto-revocation | | Audit Logging | ❌ | ✅ Completo | | High Availability | ❌ | ✅ Replication | | **Vault API Compatible** | ❌ | ✅ Migration path | --- ## Next Steps 1. **Validar arquitectura** - ¿Tiene sentido este scope? 2. **Naming** - ¿`secretumvault`, `svault`, otro? 3. **Prioridades** - ¿Qué implementar primero? 4. **Cedar policies** - ¿Es la mejor opción o prefieres ACL simple? 5. **Integración RustyVault** - ¿Backend? ¿Fork? ¿Proyecto separado? **¿Empezamos con Phase 1 en Claude Code?**