SecretHive — a self-hosted key vault
A small, self-hosted key vault for the secrets services and scripts need: vaults of versioned secrets with an API that covers everything the web UI does; a command line, a PowerShell module and an Ansible collection that fetch them at deploy time; machine identities that need no stored secret where the platform already has an identity; and an audit trail of every value read, from the first release.
Status 2026-09-15: design. Nothing is built yet; this page states what it will be and why, so what gets built can be checked against it. MIT licence; on GitHub once the identity and access model is green.
Why we are building it
Our homelab runs a few dozen services on a handful of hosts, and its secrets live where each tool happened to put them: an environment file per compose project on each host, secrets stored in the forge for CI, and a password manager for the keys people use. That works until you ask the questions a vault exists to answer. Which services use this token? Who read it last? When was it rotated, and what breaks if we rotate it now? A value copied into three files gets rotated in two.
What we want from a vault, all at once:
- Secrets in one place, grouped into vaults, versioned, with an expiry and a way back from a delete.
- Fetched by the tools already in use, at deploy time: a shell, a compose file, a CI job, Ansible, PowerShell and, later, Kubernetes. A secret that has to be pasted into a file has not really left the file.
- Machine identity without a stored secret where the platform already issues one, and API keys done properly where it does not.
- Sign-in with the identity provider we already run, rights per vault, and reading a value as a right of its own.
- Every value read on record, from the first day, in a form a monitoring system can alert on.
- Proof that it can be restored before anything depends on it.
- One container that runs on a NAS with SQLite, and with SQL Server where there is one.
The options we looked at each covered part of that list. The capable ones bring an operating model sized for a platform team; others keep single sign-on, network restrictions or audit streaming for a paid edition. SecretHive is the part we need, built on the same foundations as our other applications, and nothing more.
What sets it apart
Reading a value is its own right
Seeing that a secret exists, when it changed and when it expires is one right; reading its value is another. A job that only checks for expiring secrets never holds the right to read one. Every value read is an audit record written with the read itself: which secret and version, which identity, through which key or token, from which address, and why, if the caller said.
Machines authenticate as what they already are
A CI job, a Kubernetes service account or another workload that can present a signed token from an issuer the vault trusts exchanges it for a short-lived token scoped to one vault. Nothing is stored on either side. Where that is not possible, API keys are a first-class credential rather than a shared password: each belongs to one identity and is audited under it, is hashed and shown once, has a mandatory expiry, a vault, a level, a separate right to read values, allowed networks and a rate limit, and can be rotated with two keys active so nothing breaks in between.
Built for the tools already there
secrethive run -- docker compose up -dstarts a command with the secrets it references in its environment, so no secret is written to disk on the host.- A PowerShell module for Windows PowerShell 5.1 and PowerShell 7 that also registers as a SecretManagement vault, so
Get-Secret -Vault SecretHiveworks in scripts that already useGet-Secret. - An Ansible collection with a lookup plugin and a module per resource.
- A CI step that fetches through a token exchange.
- A documented recipe for the External Secrets Operator on Kubernetes.
The web UI uses the same API as all of these, so there is nothing the UI can do that a script cannot.
Recovery before trust
A vault that cannot be restored is a liability. One command writes a consistent, encrypted backup and one restores it into an empty instance; the restore runs as a test on every build. The master key is never inside the backup. An emergency export of a vault opens with a stand-alone tool and no server, for the day the server is the problem. The health endpoint reports the age of the last verified backup.
Your identity provider
Local accounts, and OpenID Connect against any provider (Authentik, Microsoft Entra ID, Google, Keycloak), several at once, configured on the admin pages without a restart. Groups, with provider groups feeding SecretHive groups, and roles per vault: read metadata, read values, manage secrets, manage the vault.
Safe by default
- Nothing is anonymous, on any vault, ever.
- Every value is encrypted with its own data key, and data keys with a master key held outside the database.
- A vault and a key can each be limited to listed networks.
- Values never appear in logs; a test fails the build if one could.
- The audit trail is append-only, and events that should never pass quietly carry a security severity: a burst of failed sign-ins, a value read by a disabled identity, a bulk read, a new administrator, a refused network, a purge, a stale backup, a master key that fails to unwrap.
At a glance
- Vaults of secrets with versions, tags, content type, enable and disable, not-before and expiry dates
- Soft delete with a retention period, recovery, and purge protection per vault
- A REST API with an OpenAPI description, and a web UI that is a client of it
- A command line:
get,set,runwithsecrethive://vault/namereferences, and the stand-alone export reader - A PowerShell module with a SecretManagement vault, and an Ansible collection
- Token exchange for workload identities; API keys owned by an identity
- Roles per vault, allowed networks per vault and per key, rate limits
- An audit log with an admin page; structured JSON logs; OpenTelemetry metrics and traces; a health endpoint that reports facts a monitoring system can threshold
- Backup, restore, and an emergency export
Where it runs
One container image, built for the strictest target and therefore fine everywhere else:
- A single container with SQLite and a local volume: a NAS, a small VM, a developer machine. This is the mode it is designed around.
- Kubernetes or OpenShift: SQL Server and several replicas. The image runs as a non-root, arbitrary UID on port 8080.
Roadmap
- Core. Vaults, secrets and versions, envelope encryption with a written threat model, the API, a minimal UI, and the audit log, structured logging and health endpoint built in the same phase.
- Identity and access. Accounts, OpenID Connect, groups, roles per vault, API keys and allowed networks. The repository goes public here.
- The tools. The command line, the PowerShell module and the Ansible collection.
- Recovery. Backup, restore, the restore test, the emergency export and its reader. Nothing real is stored in SecretHive before this phase is green.
- Workload identity. Token exchange for CI jobs and Kubernetes service accounts, and the External Secrets recipe.
- Moving in. The first real secrets, the published list of security events with a sample alert rule for each, and a hardening review.
Later, if asked: certificates as their own objects with expiry alerts, and keys that sign and wrap without ever leaving the vault.
Name
SecretHive: it keeps secrets, and it sits alongside the other Hive applications.