Access model
A secret can inherit project permissions or use explicit bindings only. Reveal goes through an approval workflow and issues a time-limited grant.
Self-hosted · AGPL-3.0 · built for engineering teams
Store credentials, certificates, and configuration in one place. PostgreSQL row-level security enforces access at the database, while audit logs record every sensitive action.
Access model
A secret can inherit project permissions or use explicit bindings only. Reveal goes through an approval workflow and issues a time-limited grant.
export GLOBAL_ADMIN_EMAIL=you@example.com
ALLOW_INSECURE_DEFAULTS=1 \
podman-compose up -d --build
# UI http://localhost:8080
# PostgREST http://localhost:3000
Manage access, rotate credentials, and connect workloads through the browser, CLI, machine API, or PostgREST.
/eso/v1corvus CLI: get, apply, reveal, approve, denyRLS in PostgreSQL rejects unauthorized rows even when application code is wrong.
| Layer | Control |
|---|---|
| Encryption | Fernet (AES-128-CBC + HMAC) at rest via MASTER_KEY. Optional per-project data-encryption keys. |
| Key protection | An optional HSM stores master-key material outside the application. Local HSM state lives in hsmdata. |
| Authorization | PostgreSQL RLS policies. SECURITY DEFINER functions for auth flows. |
| Sessions | Server-side sessions with per-device revocation. Login lockout after 5 attempts / 5 minutes. |
| Credentials | bcrypt hashing in SQL. Production refuses to start without strong generated secrets. |
Use the browser for daily work, the CLI for shells and CI, and the machine API for workloads. Kubernetes connects through External Secrets Operator.
Interfaces
/eso/v1 with machine tokens or PATs.corvus for shells and CI. Python 3 stdlib only.Deploy
corvus-cli
is a stdlib-only client for /eso/v1. Binary name is
corvus. Machine tokens stay on one project. PATs can switch projects by name and run org commands.
Install
RHEL 9+. Env vars beat ~/.config/corvus/config (mode 0600).
SS_URL, SS_TOKEN, SS_PROJECTss_… machine token: project UUID onlypat_… PAT: UUID or unique project name--from-file / --from-env over --valuesudo install -m 0755 corvus /usr/bin/corvus
sudo install -m 0644 corvus.1 /usr/share/man/man1/corvus.1
# or: make rpm && sudo dnf install -y dist/corvus-cli-*.noarch.rpm
# Machine token: project UUID only
corvus login \
--url https://secrets.example.com \
--token ss_… \
--project 31a70875-7d6a-40a7-a315-751f8a7ee38f
# PAT: project name is fine
corvus login \
--url https://secrets.example.com \
--token pat_… \
--project ios-app
# CI / no config file
export SS_URL=https://secrets.example.com
export SS_TOKEN=ss_… # do not commit
export SS_PROJECT=<uuid>
#!/usr/bin/env bash
set -euo pipefail
# Create a secret from a file
corvus apply secret DB_PASSWORD \
--from-file=./db-pass.txt \
--note "initial prod DB password"
# Create from an env var
export SENTRY_DSN="https://…@sentry.io/42"
corvus apply secret SENTRY_DSN --from-env=SENTRY_DSN
# Create a KV secret with custom fields
corvus apply secret stripe/prod \
--from-env=STRIPE_SECRET_KEY \
--field 'note=live key, rotate quarterly' \
--field 'kind=api-key'
# List all secrets in the project (metadata only, no values)
corvus get secrets
# Filter by key prefix
corvus get secrets -l stripe
# Show one secret's metadata
corvus get secret DB_PASSWORD
#!/usr/bin/env bash
set -euo pipefail
export DATABASE_URL
DATABASE_URL="$(corvus get secret DATABASE_URL -o value)"
psql "$DATABASE_URL" -c 'SELECT 1'
# Hierarchical keys work
corvus get secret prod/db/password -o value
# List metadata only (no values), filter key/note/custom fields
corvus get secrets -l platform-team
#!/usr/bin/env bash
set -euo pipefail
openssl rand -base64 32 \
| corvus apply secret APP_SESSION_KEY --from-file=-
NEW="$(openssl rand -hex 24)"
export NEW
corvus apply secret API_KEY --from-env=NEW --note "rotated in CI"
unset NEW
export API_KEY
API_KEY="$(corvus get secret API_KEY -o value)"
./deploy.sh
# Caller
corvus reveal secret API_KEY --reason "debugging prod auth #1234"
# Project admin or team owner
corvus get requests
corvus approve <request-id> --minutes 15
# corvus deny <request-id>
corvus get secret API_KEY -o value
# Machine tokens (ss_…) skip human ACL and reveal approval
#!/usr/bin/env bash
set -euo pipefail
: "${SS_URL:?}" "${SS_TOKEN:?}" "${SS_PROJECT:?}"
if [[ -n "${BUILD_API_KEY:-}" ]]; then
corvus apply secret BUILD_API_KEY \
--from-env=BUILD_API_KEY \
--note "ci ${CI_COMMIT_SHA:-local}"
fi
export DATABASE_URL
DATABASE_URL="$(corvus get secret DATABASE_URL -o value)"
./run-migrations.sh
Full command list, org admin verbs, and token scopes: github.com/sigaint-au/corvus-cli
The public demo uses seeded mock accounts. Local setup is one compose command. Keep real secrets off both until you deploy for production.
Demo accounts
Password is password for all of them. Evaluation only.
scripts/reset.sh # asks first
scripts/reset.sh --yes # does not
# Drops pgdata only.
# HSM state stays in hsmdata.