Sign inSign up

chrweav/vault-cache

By chrweav

•Updated 3 months ago

Image
0

298

chrweav/vault-cache repository overview

⁠Vault Cache — break-glass credential cache for BeyondTrust PRA & Password Safe

A small, hardened service that periodically pulls a curated set of privileged credentials from BeyondTrust Privileged Remote Access (PRA) and/or Password Safe (Managed Accounts and Secrets Safe), stores them encrypted at rest, and serves them to break-glass consumers over mutual TLS when the source platform is unavailable. It talks to each upstream over OAuth.

  • Encrypted at rest (public-key sealed): each cached value is an anonymous X25519 sealed box; the private key needed to read it is never written to disk.
  • Operator unseal gates retrieval (M-of-N Shamir): starts sealed; a threshold of operator shares is required to read cached values — the image/host alone cannot decrypt the cache.
  • Refreshes while sealed: new values are sealed with the public key, so the cache stays current without the unseal key — keep nodes sealed and unseal only to retrieve. Upstream OAuth secrets are injected at runtime (env, or a 0600 file on the volume), never baked into the image.
  • mTLS API with per-client-CN authorization, and a tamper-evident, hash-chained audit log.
  • Self-configuring: a first-boot setup wizard validates your credentials, generates the mTLS certificates, writes the config, initializes the store, prints your unseal shares, and (optionally) stores the OAuth secret on the volume for a self-contained node — nothing to build.
  • Built-in operator client: vault-cache client … unseals and retrieves cached credentials over mTLS — readable tables, single-field extraction, or JSON. No curl required.
  • The image contains no secrets and no tenant configuration.

⁠Tags

  • :latest — latest (moving).
  • :<version> — pinned / immutable (e.g. :0.5.1).

⁠Prerequisites

Podman on Linux or WSL2 (Ubuntu): sudo apt-get install -y podman (or sudo dnf install -y podman).

At least one upstream, provisioned by an admin first (this can't be done from the container):

  • PRA — create a Configuration-API account (copy its OAuth client id / secret); a dedicated break-glass Account Group + Account Policy with Allow simultaneous checkout = ON and Auto-rotate on check-in = OFF; place only the break-glass accounts in that group and note its account_group_id. (A PRA API account can read the entire vault — the curated group is the scope.)
  • Password Safe — create an application user with an API Access Policy registration (no client certificate); copy its client id / secret. Grant it access to only the break-glass Managed Accounts (via a Smart Group) and read on only the break-glass Secrets Safe folders, with an access policy that auto-approves, allows concurrent requests, and does not change the password on release. (Password Safe scopes the API user server-side.)

⁠Quick start (Podman)

IMG=docker.io/chrweav/vault-cache:latest

# 1) one-time interactive setup wizard — writes config + certs + store to a named volume
podman pull "$IMG"
podman run --rm -it -v vault-cache-state:/var/lib/vault-cache "$IMG" setup
#    answer the prompts (it validates your credentials live); RECORD the printed unseal shares.
#    On plain WSL, answer "No" to the memory-hardening prompt.

# 2) run it (starts SEALED), published on loopback
podman run -d --name vault-cache \
  --read-only --cap-drop=ALL --security-opt=no-new-privileges \
  --memory=256m --pids-limit=128 \
  --publish=127.0.0.1:8443:8443 --tmpfs=/tmp:rw,noexec,nosuid,nodev,size=8m \
  -v vault-cache-state:/var/lib/vault-cache "$IMG"
#    On a Linux host with mlockall allowed, also add:
#      --cap-add=IPC_LOCK --ulimit=memlock=67108864:67108864

# 3) unseal with the threshold of shares — simplest via the built-in client INSIDE the container
#    (config + certs already on the volume; it prompts for each share, hidden — repeat per custodian):
podman exec -it vault-cache vault-cache --config /var/lib/vault-cache/config.toml client unseal
podman exec -it vault-cache vault-cache --config /var/lib/vault-cache/config.toml client status
#    status shows "sealed": false once the threshold is reached

⁠Retrieve break-glass credentials (after unseal)

Use the built-in client — no curl required. Inside the running container the config + certs are already present, so connection details are auto-filled:

VC="podman exec -it vault-cache vault-cache --config /var/lib/vault-cache/config.toml client"
$VC status                         # sealed?, cached counts, version
$VC pra accounts                   # PRA: cached accounts (metadata)
$VC pra credential <id>            # PRA: the secret material
$VC ps accounts                    # Password Safe: managed accounts
$VC ps secrets                     # Password Safe: Secrets Safe items
$VC ps secret <guid>               # Password Safe: a Secrets Safe value (--field value for just it)

Add --json for raw output, or --field <name> to print a single value for scripting. Prefer raw HTTP or a remote workstation? Copy the certs out (podman cp vault-cache:/var/lib/vault-cache/certs/. .) and either curl the /v1/* endpoints or point the client with --url/--cacert/--cert/--key (or the VAULT_CACHE_* env vars).

⁠Operating notes

  • Sealed by design — the cache refreshes while sealed, so keep nodes sealed and submit the share threshold only when you need to retrieve during an incident. For resilience, run multiple independent sealed caches on separate hosts (no load balancer or clustering needed).
  • Credentials: the upstream OAuth secret is injected at runtime — the wizard offers to store it in a 0600 file on the volume (self-contained) or you set VAULT_CACHE_*_CLIENT_SECRET at run.
  • State (config, certs, encrypted store, audit log) lives in the vault-cache-state volume; back it up. The cached values are useless without the unseal shares.
  • Updates: podman pull the new tag and recreate the container; the volume persists. vault-cache client status (or GET /v1/status) reports the running version. (Upgrading from 0.4.x: the store format changed in 0.5.0 — re-run setup into a fresh volume; the cache repopulates from upstream.)
  • Run on a host independent of the platform the cache protects (an outage shouldn't take the cache down too).

⁠Troubleshooting

  • not configured … run … setup — the container was started before the setup wizard populated the volume. Run step 1 first (into the same vault-cache-state volume).
  • memory hardening required but failed (common on WSL) — re-run setup and answer No to the hardening prompt (or add --cap-add=IPC_LOCK + --ulimit=memlock=67108864:67108864).
  • 503 {"error":"sealed"} — not unsealed yet (step 3). The client prints this as a clear "cache is SEALED" message.
  • curl TLS errors — copy the wizard-generated certs out (podman cp vault-cache:/var/lib/vault-cache/certs/. .) and pin server.crt with --cacert; the URL host must match a SAN in server.crt. (Using the built-in client inside the container avoids this entirely.)
  • Wizard validation fails / "could not resolve host" (WSL) — the container can't reach your PRA / Password Safe site (split-DNS / VPN); confirm it resolves and is reachable from the host.

Tag summary

Content type

Image

Digest

sha256:c4025b270…

Size

11.8 MB

Last updated

3 months ago

docker pull chrweav/vault-cache