100 lines
5.5 KiB
JSON
100 lines
5.5 KiB
JSON
{
|
|
"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"
|
|
}
|