{ "alternatives_considered": [ { "option": "HashiCorp Vault", "why_rejected": "BSL license incompatible with open distribution. Go binary introduces subprocess overhead. HCL policies require a second policy language alongside Cedar. No Rust-native integration." }, { "option": "Extend SOPS+Age to handle dynamic secrets", "why_rejected": "SOPS is a file encryption tool, not a secrets engine. TTL, auto-rotation, and audit trails are not concepts SOPS is designed for. Extending it would be a reimplementation of a secrets engine with worse UX." } ], "consequences": { "negative": [ "HA deployment requires 3-node Raft cluster — additional infrastructure for production", "Age key at `${data_dir}/vault/master.age` is the only bootstrap credential — requires chmod 600 and secure backup", "Local path dependency — requires secretumvault repo checkout alongside provisioning" ], "positive": [ "Dynamic credential TTL and auto-rotation for database passwords and tokens", "Cedar-gated secret access with audit trail — compliance-ready", "Solo mode uses filesystem age key — no infrastructure dependency for single-operator deployments", "Consistent authorization model: Cedar governs both infrastructure operations and secret access" ] }, "constraints": [ { "check": { "must_be_empty": false, "paths": [ "platform/secretumvault/" ], "pattern": "secretumvault", "tag": "Grep" }, "claim": "SOPS+Age handles static gitops secrets; SecretumVault handles runtime dynamic secrets — no overlap", "id": "sops-and-vault-complementary", "rationale": "Mixing the two systems creates ambiguity about which is authoritative for a given secret class. Clear separation prevents accidental migration of static secrets into the vault.", "scope": "platform/secretumvault/", "severity": "Hard" }, { "check": { "must_be_empty": false, "paths": [ "platform/secretumvault/" ], "pattern": "cedar|authorize", "tag": "Grep" }, "claim": "All SecretumVault read operations must be authorized via Cedar policies — no bypass path", "id": "cedar-governs-vault-access", "rationale": "Cedar is the single authorization point for the platform. Vault access bypassing Cedar creates an unaudited path to secrets.", "scope": "platform/secretumvault/src/", "severity": "Hard" }, { "check": { "cmd": "rg 'master.age' --include='*.rs' platform/ | grep -v '0o600\\|0600'", "expect_exit": 1, "tag": "NuCmd" }, "claim": "The bootstrap age key at vault/master.age must be chmod 600 and must be the only file-based credential", "id": "vault-age-key-permissions", "rationale": "The age key is the bootstrap trust anchor. If it is world-readable, the entire vault is compromised.", "scope": "platform/secretumvault/src/solo.rs", "severity": "Hard" } ], "context": "The platform manages two distinct classes of secrets: (1) static gitops secrets — API keys, TLS certs, SSH keys committed as encrypted SOPS+Age files; (2) dynamic runtime secrets — temporary database passwords, short-lived tokens, auto-rotating credentials. SOPS+Age handles class 1 well but has no concept of TTL, auto-rotation, or access audit trails. HashiCorp Vault handles class 2 but is Go binary (not Rust-native), uses BSL license (not permissive), and uses HCL policies (incompatible with Cedar authorization model).", "date": "2026-01-08", "decision": "SecretumVault provides dynamic runtime secrets management. It is embedded in the platform as a Rust-native library (path dependency `../../../Development/secretumvault`) with Cedar policy enforcement, SurrealDB-backed storage, and filesystem backend for solo mode (age key at `${data_dir}/vault/master.age`). SOPS+Age remains for static gitops secrets. SecretumVault complements, not replaces, SOPS.", "id": "adr-018", "ontology_check": { "decision_string": "SecretumVault provides dynamic runtime secrets with Cedar authorization; SOPS+Age remains for static gitops secrets; complementary, not competing", "invariants_at_risk": [ "solid-boundaries" ], "verdict": "Safe" }, "rationale": [ { "claim": "Rust-native: zero subprocess overhead, same authorization model as the platform", "detail": "SecretumVault is linked as a Rust library. No subprocess, no gRPC, no network hop for secret retrieval. Cedar policies for secrets are evaluated by the same Cedar engine used for infrastructure authorization — one policy model, one audit trail." }, { "claim": "HashiCorp Vault rejected: BSL license and HCL policies incompatible with platform constraints", "detail": "BSL license restricts commercial use without a subscription. HCL policies require maintaining a separate policy language alongside Cedar. Neither aligns with the platform's Rust/Cedar/Nickel stack." }, { "claim": "SOPS+Age remains authoritative for static gitops secrets", "detail": "Static secrets (API keys in config, TLS certs) are already gitops-managed via SOPS. Replacing SOPS would break the gitops workflow and add migration risk. SecretumVault handles only runtime-dynamic secrets." } ], "related_adrs": [ "adr-014-solid-enforcement", "adr-015-solo-mode-architecture" ], "status": "Accepted", "title": "SecretumVault — Dynamic Secrets Complementary to SOPS+Age" }