← All projects
Secrets management

uBixVault

v1.0.0 Go · BSD-3-Clause · Vault-compatible API

A from-scratch secrets manager in Go. It stores and generates secrets behind an encrypted, sealed barrier — and speaks a Vault-compatible HTTP API, so tools you already have can talk to it unchanged.

Language
Go
License
BSD-3-Clause
Interface
Vault-compatible HTTP
At rest
AES-256-GCM
Synopsis
shell
ubixvault server -data <dir> [-audit-log <file>]
          [-tls-cert <f> -tls-key <f>]
ubixvault operator init | unseal | seal-status
Description

All data at rest is AES-256-GCM encrypted — storage never sees plaintext, and the storage path is bound into the ciphertext so blobs can't be relocated.

The vault boots sealed. Its master key is reconstructed from Shamir k-of-n key shares before any secret is readable — or, given a key-encryption key, the vault can auto-unseal itself on restart, with recovery keys to regenerate a lost root token. Access is default-deny, path-based tokens with ACL policies, and audit logging is fail-closed — the client token is HMAC'd, never logged in the clear.

A built-in web console at /ui/ manages secrets (with version history), policies, and tokens, and a Prometheus metrics endpoint exposes seal state and request counts for scraping.

Examples
build & run (dev)
# build and run in dev mode (plain HTTP, audit on)
$ go build -o bin/ubixvault ./cmd/ubixvault
$ ./bin/ubixvault server -data ./data -audit-log ./audit.log
initialize
# 3 unseal shares, threshold 2
$ curl -s -X POST $VAULT/v1/sys/init \
    -d '{"secret_shares":3,"secret_threshold":2}'
-> {"keys":["k0","k1","k2"], "root_token":"uv...."}
unseal & write a secret
$ curl -s -X POST $VAULT/v1/sys/unseal -d '{"key":"k0"}'
$ curl -s -X POST $VAULT/v1/sys/unseal -d '{"key":"k1"}'
$ curl -sH "$T" -X POST $VAULT/v1/secret/data/app \
    -d '{"data":{"api_key":"sk-123"}}'
deploy on Kubernetes (Helm)
# single-node chart: StatefulSet, auto-unseal, TLS
$ kubectl create secret generic uv-kek \
    --from-literal=auto-unseal-key=$(head -c32 /dev/urandom|xxd -p|tr -d '\n')
$ helm install vault ./deploy/charts/ubixvault \
    --set tls.existingSecret=uv-tls --set autoUnseal.existingSecret=uv-kek
operate
$ curl -s $VAULT/v1/sys/health    # readiness (200/503/501)
$ curl -s $VAULT/v1/sys/metrics   # Prometheus text format
# manage it from the web console at $VAULT/ui/
Capabilities
Encryption barrier
AES-256-GCM at rest; the storage path is bound into the ciphertext so blobs can't be relocated.
Seal / unseal
In-house, constant-time Shamir over GF(2⁸). Nothing is readable until it's unsealed.
Tokens & ACL policies
Default-deny, path-based capabilities. Hand out scoped, non-root tokens.
KV v2 & Transit
Versioned secrets, plus crypto-as-a-service: encrypt/decrypt, rewrap, wrapped data keys, HMAC, sign/verify with ECDSA or Ed25519 keys, and per-context key derivation with optional convergent (deterministic) encryption — keys never leave the vault.
Dynamic database credentials
Short-lived MariaDB users generated on demand and auto-revoked on lease expiry.
Web admin console
A built-in console at /ui/ to manage KV secrets (with version history), ACL policies, and tokens — served from the binary, no external assets.
Metrics & health
Prometheus metrics (seal state, uptime, request counts), a readiness endpoint, and a dedicated liveness endpoint (/v1/sys/livez) that stays green while sealed — so probes never crash-loop a vault waiting to be unsealed.
Kubernetes-native
Deploy with the bundled single-node Helm chart; pods authenticate with their ServiceAccount token, and the vault auto-unseals on restart — with recovery keys to regenerate a lost root token.
Authentication methods
Tokens, AppRole and Kubernetes ServiceAccount auth for machines, userpass (username + PBKDF2-hashed password) for people, JWT/OIDC (signed tokens verified against static keys, a JWKS, or an OIDC issuer's discovery document), TLS client certificates (mutual-TLS, verified against a trusted CA or a pinned cert), and LDAP / Active Directory (bind + group search, groups mapped to policies or fed to identity external groups) — each mapped to policies.
Identity
One entity per subject, with aliases mapping each auth-method login to it and groups (nestable) that carry policies — so a person's several logins share one identity, and policy attached to an entity or group applies across every method they log in through, taking effect without re-issuing tokens.
Cubbyhole
Per-token private storage: a scratch space readable and writable only by the token that wrote it — no policy, not even root, reaches another token's cubbyhole — and destroyed when that token is revoked.
Rate limiting
Optional per-client token-bucket throttling to blunt brute-force against unseal shares and tokens; health, metrics, and the console are exempt.
Certificate authority
A built-in PKI engine: generate an internal root CA (its key never leaves the vault) and issue short-lived, role-constrained TLS certificates on demand.
Flexible auto-unseal
Shamir shares, a local key-encryption key, a transit seal via another vault, or a cloud KMS / HSM through an external command — the wrapping key stays off the host, and no provider SDK lives in the vault.
Response wrapping
Wrap a secret in a single-use, short-lived token and hand that to a consumer instead of the secret — unwrapped exactly once, then destroyed.
Durable database storage
Run against a MySQL/MariaDB database instead of a local disk, so the node is replaceable — it restarts against the same replicated store. The database sees only ciphertext; the vault creates its own tables.
Rotation & backups
Rotate the unseal shares live with rekey (no downtime), and schedule off-node encrypted snapshots — plus snapshot/restore for migration between backends.
Configuration

Configuration reference.

The settings you'll actually reach for — the full reference lives in the deployment docs.

Server & CLI
SettingDefaultNotes
server -storage <file|mysql>filemysql keeps the encrypted store in a MySQL/MariaDB database — durable, replaceable node.
server -data <dir>./dataDirectory for the encrypted store (-storage file).
server -storage-mysql-dsn$UBIXVAULT_STORAGE_DSNDSN for -storage mysql. Passed via env, never on the command line.
operator rekey init / updateRotate the Shamir unseal shares live — no downtime, no data re-encryption.
server -tls-cert / -tls-keyEnable HTTPS. Without them the server logs a loud no-TLS warning (dev only).
server -audit-log <path>Turns on fail-closed audit logging to that file.
server -auto-unseal-key <hex>$UBIXVAULT_AUTO_UNSEAL_KEYHex 32-byte key-encryption key; enables auto-unseal on restart.
operator init -shares / -threshold5 / 3Shamir k-of-n split created at initialization.
-address$UBIXVAULT_ADDRClient → server address for the CLI.
-token$UBIXVAULT_TOKENClient auth token for the CLI.
-ca-cert / -tls-skip-verifyClient TLS trust. Skipping verification is insecure — dev only.
Helm chart · values.yaml
ValueDefaultNotes
containerPort / service.port8200Vault-compatible API port.
storage.type / storage.mysql.dsnSecretfile · —mysql uses a database; the DSN comes from a Secret (never a chart value) and the data PVC is dropped.
persistence.size / mountPath1Gi · /var/lib/ubixvaultEncrypted data volume (StatefulSet PVC), for storage.type=file.
backup.enabled / schedulefalse · 0 */6 * * *Scheduled off-node snapshot CronJob using a least-privilege token.
autoUnseal.existingSecretSecret holding the KEK; auto-unseal is on by default.
tls.existingSecret / tls.certManagerBring your own cert, or issue one via cert-manager.
audit.enabledfalseFail-closed audit log to its own PVC.
rateLimit.enabled / perSecondfalse · 20Per-client token-bucket limit (burst 40).
kubernetesAuth.enabledtruePods authenticate with their ServiceAccount token.
metrics.serviceMonitor.enabledfalseScrape via the Prometheus Operator.
ingress.enabledfalseExpose over an ingress with TLS.
Architecture

Layered, and sealed at the base.

Every request passes down through the same layers, and everything at rest sits below the barrier.

The stack
HTTP API · CLI
clients enter here — Vault-compatible /v1/*
Auth Methods → Token & Lease Manager
Policy (ACL) engine · Identity
Secrets Engines
KV v2 · Transit · Database-dynamic · PKI · Cubbyhole
Audit Devices
broker → file / syslog · fail-closed
Barrier — AES-256-GCM at rest
Seal / Unseal · Shamir k-of-n
Storage Backend
file today · Raft later
How it holds

A request enters through the Vault-compatible HTTP API (or the ubixvault CLI), is authenticated to a token, and checked against default-deny path ACLs before any secrets engine runs. Every request and response passes through the audit broker on the way through.

Beneath all of it sits the barrier: everything written to storage is AES-256-GCM encrypted, with the storage path and format version bound in as authenticated data — so a ciphertext only decrypts at the exact path it was written to, and can't be relocated.

The vault boots sealed, holding only ciphertext. Unsealing reconstructs the master key from Shamir k-of-n shares. The key hierarchy — unseal shares → master key → barrier key → data — lets the barrier key rotate without re-sharing.