We actually just ported SecureStore to go, it’s sort of like this but with cross platform clis and intended to also allow sharing secrets across services and languages, in a secure and embedded fashion! It’s available in rust, php, .net, JS/TS, Python, and golang and easy to port to others.

I didn’t get a chance to do a write up but the golang port is here: https://github.com/neosmart/securestore-go

The approach to crypto is very different, we went with what’s very well understood and very well supported on all platforms with little or no dependencies (eg we can use web crypto in JS frontend or backend with no external libs or crypto JS library nonsense).

The original .NET and Rust code is from over a decade ago and carefully architected (well before vibecoding was a thing), the secrets are stored in a human readable (json) vault that can be embedded in your binaries or distributed alongside them and be decrypted with either password-based or key-based decryption (or both).

The rust repo has the most info: https://github.com/neosmart/securestore-rs

blastslot4 days ago | | | parent | | on: 47718833
That’s actually a pretty interesting tradeoff — especially going with “boring crypto” that’s widely supported vs pulling in heavier deps.

The JSON vault + cross-language portability is nice too, especially if you’re embedding secrets across services without tying yourself to one runtime. Curious how you handle key management at scale though — that’s usually where these systems get tricky more than the crypto itself.

ComputerGuru4 days ago | | | parent | | on: 47719875
SecureStore is an open spec/protocol for managing secrets in a secure and portable manner, while it defines the decryption key formats (currently: key-based, password-based, or a mix of both interchangeably) it doesn't get into the mechanics of key management, which are "trivial and left as an exercise for the reader."

More seriously though, you're supposed to use separate vaults (with the same keys, where "keys" is the name of the secrets, not the decryption keys) for testing/staging/production, e.g. perhaps secrets.{testing,production,staging}.json and the same secrets.{testing,production,staging}.key for the decryption keys, and store both the username and password in them (after all, it's just an encrypted, glorified KV store) so that you don't have to hard-code any usernames and conditionally load them based on the environment in your code (so db:username is one "secret" and db:password is another (actual) secret).

The secrets vaults (the secrets.json files) are non-sensitive and can be versioned and pushed to your server the same way you push the binaries. Now how you move the secrets to the server is up to you. You could do it the old-fashioned way and just have it as an environment variable, in which case even when your env vars leak at least you haven't leaked your api keys, only the key to decrypt them (which you'd then rotate), but that's not a recommended option. Ideally you'd instead use whatever secure channel you use to init/stage the servers to begin with to transfer the secure key files - the key files are generally immutable, even as the secrets change, so you only have to do this once (ideally via a high-friction, high-auth mechanism, for most people not at FAANG scale, probably manually).

You can also use whatever additional layer of abstraction on top of the symmetric SecureStore decryption key you like. For example, you could asymmetrically encrypt the keyfiles and then each host would decrypt it with its own private key, or have a secrets side channel that's just used to obtain the static decryption key over the local network, or use your operating system's encryption facilities to transmit it, whatever works for you at whatever point on the complexity/security curve you desire.

(These are all just options, none are official recommendations.)