Monitor and track expiring secrets across your Vault infrastructure
Chronowarden is a secret lifecycle observability service that syncs with your secret providers, tracking TTLs and rotation requirements through custom metadata. It provides a web UI and REST API to visualize secret health and alert on expiring credentials.
This is very early work being built with focus on compliance for financial institutions (PCI DSS 4.0, DORA) and best practices (NIST SP 800-63B-4) regarding credential rotation.
Join us on Matrix to discuss and troubleshoot!
- Vendor neutrality - Connect to multiple backends instances simultaneously
- Credential Health Dashboard - Visual status of secrets (OK, Warning, Expired, No TTL)
- Severity Levels - Classify secrets by (user-defined) compliance requirements (PCI-DSS, Critical, Default)
- Secure - Never reads actual secret values, only metadata
- Real-Time Sync - Live and on-demand synchronization with backends
- Prometheus Metrics - Built-in monitoring endpoint for alerting
- Modern Web UI - SvelteKit frontend with dark mode
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Vaults │ ───► │ Chronowarden │ ───► │ Web UI │
│ (Multiple) │ │ Backend │ │ (Svelte) │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌──────────────┐
│ SQLite DB │
│ (Metadata) │
└──────────────┘
docker run --network=host --rm -p 8000:8000 \
-v $(pwd)/config.yaml:/data/config.yaml \
fajfer/chronowarden:0.0.1Add -v $(pwd)/chronowarden.db:/app/chronowarden.db if you already have a DB
Production (default) — distroless, no shell, 86MB
docker build -t fajfer/chronowarden:0.0.1 .
Development — full shell, git, --reload, 286MB
docker build --target dev -t fajfer/chronowarden:0.0.1-dev .
- Python 3.11+
- Node.js 18+ (for frontend)
- Docker (optional, for dev Vaults)
-
Install dependencies:
uv sync
-
Configure vaults:
Copy the example config and add your Vault instances:
cp config.example.yaml config.yaml
Edit
config.yaml:vaults: production: url: https://vault.example.com token: your-vault-token verify_ssl: true max_versions_per_secret: 5 severity_levels: critical: rotation_period_days: 30 alert_threshold_days: 7 pci-dss-4.0: rotation_period_days: 90 alert_threshold_days: 14 default: rotation_period_days: 365 alert_threshold_days: 30
-
Run the server:
uv run uvicorn chronowarden:app --reload
API will be available at
http://localhost:8000
-
Install dependencies:
cd frontend npm install -
Run development server:
npm run dev
UI will be available at
http://localhost:5173
For local testing with dev Vault instances:
python dev-setup.pyThis script:
- Starts OpenBao (port 8200) and Vault (ports 8201, 8202) containers
- Extracts root tokens from logs
- Creates
config.yamlwith all dev vaults configured
Cleanup:
docker stop dev-vault-1.20.1 dev-vault-1.21.3 openbao-dev
docker rm dev-vault-1.20.1 dev-vault-1.21.3 openbao-devChronowarden requires read/write access to secret metadata only. It never reads actual secret values.
Required capabilities:
# For KV v2 engines
path "secret/metadata/*" {
capabilities = ["read", "list", "update"]
}
# Optional: engine discovery
path "sys/mounts" {
capabilities = ["read"]
}Custom metadata fields:
chronowarden_ttl- Target rotation period (ISO8601 duration)chronowarden_severity- Severity level (user-defined)chronowarden_enabled- Whether to track this secret (true/false)
GET /api/v1/secrets- List all tracked secrets with metadata- Query params:
vault_name,engine_id,severity,enabled
- Query params:
GET /api/v1/secrets/{id}- Get secret metadata by IDPATCH /api/v1/secrets/{id}- Update secret metadata (severity, enabled, ttl)
POST /api/v1/sync- Trigger synchronization with Vault instances- Scans all configured vaults and updates local cache
GET /api/v1/vaults- List configured Vault instances with connection status
GET /health- Health check endpointGET /metrics- Prometheus metrics
| Status | Description | Condition |
|---|---|---|
| 🟢 OK | Secret is healthy | days_remaining > alert_threshold |
| 🟡 Warning | Rotation needed soon | 0 < days_remaining ≤ alert_threshold |
| 🔴 Expired | Rotation overdue | days_remaining ≤ 0 |
| ⚪ No TTL | No rotation configured | chronowarden_ttl not set |
Unit tests:
uv run pytestWith coverage:
uv run pytest --cov=chronowarden --cov-report=htmlTest compatibility with both HashiCorp Vault and OpenBao:
OpenBao (port 8200):
docker run -p 127.0.0.1:8200:8200 --name openbao-dev --detach quay.io/openbao/openbaoHashiCorp Vault (port 8201):
docker run -p 127.0.0.1:8201:8201 --cap-add=IPC_LOCK \
-e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8201' \
-d --name=dev-vault hashicorp/vaultChronowarden maintains compatibility with both platforms as OpenBao intends to remain API compatible.
See deploy/ for:
- Docker Compose setup (
deploy/compose/) - Kubernetes manifests (
deploy/kubernetes/)
- RBAC support
- Support assigning each secret/engine/provider with internal systems
- Generate automatic reports from Chronowarden for internal systems
- Better support for routing alerts
- Support additional backends for public cloud providers and their vaults
Licensed under the EUPL-1.2 - see LICENSES/ for full text.
Community support is available through Matrix channel as well as issues on GitHub
For commercial support, consultations and training feel free to reach me via email at damian (at) fajfer.org to discuss your needs and get a custom quote.