Secrets Vault
The Shield Secrets Vault provides encrypted secret storage with tenant isolation, versioning, and automatic rotation. It serves as the centralized secret management layer for the ContextUnity service mesh.
Architecture
Project SDK Shield Service │ │ ├── GetSecret(path) ──────────▶│ → SecretBackend.get() ├── PutSecret(path, value) ───▶│ → SecretBackend.put() + encrypt ├── ListSecrets(prefix) ──────▶│ → SecretBackend.list() └── RotateSecret(path) ───────▶│ → SecretBackend.rotate() │ ┌────┴────┐ │ Backend │ ├─────────┤ │ EnvStore │ ← Default (env vars) │ PgStore │ ← Planned (PostgreSQL) │ Vault │ ← Planned (HashiCorp) └─────────┘Secret Model
Every secret carries metadata alongside its value:
| Field | Type | Description |
|---|---|---|
path | str | Hierarchical path (e.g. project/api-keys/openai) |
version | int | Monotonically increasing version number |
created_at | datetime | When this version was created |
updated_at | datetime | Last modification timestamp |
expires_at | datetime? | Optional TTL for auto-expiry |
created_by | str | Identity that created this secret |
tenant_id | str | Tenant isolation boundary |
tags | dict | Arbitrary key-value metadata |
encryption_backend | str | Which encryption was used (fernet, none) |
Backend Factory
The backend is selected via configuration:
from contextunity.shield.secrets.factory import create_secret_backend
# Environment-variable backed (default)backend = create_secret_backend("env")
# PostgreSQL backed (planned)backend = create_secret_backend("postgres", dsn="postgresql://...")
# HashiCorp Vault (planned)backend = create_secret_backend("vault", url="https://vault.example.com")EnvSecretStore (Default)
The default backend reads secrets from environment variables. Secret paths map to env var names:
| Secret Path | Environment Variable |
|---|---|
project/api-keys/openai | PROJECT_API_KEYS_OPENAI |
shield/master-key | SHIELD_MASTER_KEY |
Suitable for development and single-node deployments where secrets are managed via .env files or systemd-creds.
gRPC RPCs
| RPC | Permission | Description |
|---|---|---|
GetSecret | shield:secrets:read | Retrieve a secret by path |
PutSecret | shield:secrets:write | Store or update a secret |
ListSecrets | shield:secrets:read | List secrets by prefix |
RotateSecret | shield:secrets:write | Create a new version |
All RPCs require a valid ContextToken with the appropriate permission scope. Tenant isolation is enforced at the backend level.
Encryption at Rest
Secrets are encrypted using Fernet (AES-128-CBC + HMAC-SHA256) before storage:
SHIELD_ENCRYPTION_KEY— Fernet key for secret value encryptionSHIELD_MASTER_KEY— Fernet key for PKI private key encryption
In production, these keys should be provisioned via systemd-creds rather than .env files. See Systemd Deployment for hardening details.
SDK Integration
During Project Bootstrap, the SDK automatically fetches required secrets from Shield:
- SDK presents HMAC-signed bootstrap token
- Shield validates project identity
- Shield returns LLM API keys, database credentials, etc.
- SDK caches secrets in-process (no disk writes)
This eliminates the need for projects to manage their own .env files in production.