← All churts

uBixVault 1.4 — Vault-Compatible, Checked With Vault's Own Client

uBixVault 1.4 — Vault-Compatible, Checked With Vault's Own Client

The claim I hadn’t tested

Every page about uBixVault says the same thing: it speaks a Vault-compatible API, so the tools you already have work unchanged. It’s a deliberate design decision — it’s how External Secrets Operator is supposed to plug into my cluster without anyone writing an adapter. And I’d tested it the way you test your own API: with curl, with my own client, with the requests I knew to send.

For 1.4 I tested it with HashiCorp’s own Go client — github.com/hashicorp/vault/api, the library underneath the vault CLI and External Secrets Operator. The first call it made was vault operator init. uBixVault answered 405 Method Not Allowed.

What was wrong

Four separate things, each invisible until a real client showed up:

  • PUT versus POST. Vault treats them identically on every write endpoint, and its client sends PUT. 41 of uBixVault’s write routes only accepted one of the two — including auth/kubernetes/login, the exact call External Secrets Operator makes.
  • Lists. Vault’s client lists with GET ?list=true. uBixVault only understood the LIST method.
  • Durations. Vault accepts "1h" or a number of seconds. The client sends numbers; uBixVault only took strings.
  • Extra fields. The client always sends fields uBixVault doesn’t implement — zero-valued, but present — and uBixVault rejected unknown fields. I kept that strictness where it matters: a field that would change the result (asking for PGP-encrypted unseal keys, or a limited-use token) is still refused, loudly, rather than silently ignored.

Fixing those got every step through — except reading a policy back, which crashed the client outright.

The two bugs worth the whole exercise

Chasing that crash turned up the worst one. When Vault’s client — or Terraform — writes a policy, it wraps it: {"policy": "…"}. uBixVault took that wrapper as the policy, found no paths in it, stored a policy with zero rules, and replied with success. It failed closed — an empty policy grants nothing — but any policy managed from Terraform would have quietly done nothing. That’s fixed, policies read back as text like Vault’s do, and JSON policies with keys uBixVault doesn’t understand are now refused. That last one matters more than it sounds: a restriction like allowed_parameters that gets silently dropped leaves a policy granting more than you wrote.

The other came from my own backup. Before upgrading my dev cluster I dumped the vault’s database, and the dump was nine times the size of the one from last week. 80,811 of the rows were login tokens, next to about 45 rows of actual secrets. My apps log in on every request, and two things made that pile up forever: Kubernetes auth accepted a role ttl and then ignored it, so every token lived 32 days — and nothing ever deleted a token once it expired. 1.4 applies the role’s ttl and sweeps expired tokens in the background, cleaning up what each one owned on the way out.

And a request from someone else’s directory

A team I work with runs FreeIPA, whose certificates come from its own built-in CA — one no container trusts by default. The only way to point uBixVault’s LDAP auth at it was insecure_tls, which sends the service account’s password, and every user’s password on every login, to whatever answers on that address. 1.4 adds certificate — the same field Vault uses — so the directory’s CA can be pinned instead.

What hasn’t changed

Compatibility isn’t assurance. uBixVault still has not had an independent security audit — and this release is another argument for one: every bug in it was found by pointing something outside my own head at the code. That’s what an auditor is for.

uBixVault 1.4.0 is BSD 3-Clause, on GitHub at github.com/cwolsen7905/ubixvault, tagged v1.4.0, with signed multi-arch images. If you parse policy reads yourself, note the one breaking-ish change in the release notes: data.policy is now a string, as it is in Vault.

← All churts