Yes, EnvKey uses client-side end-to-end encryption and never sends secrets to the host server in plaintext (whether it's self-hosted or you use EnvKey Cloud). So there would be no way for a cloud provider employee (or an EnvKey employee) to get access from the server side. Even the names of your variables are encrypted and not accessible except on the client.
I’m assuming the client side code isn’t keeping the secrets in some kind of TPM right? ie anyone with root access to the server or the ability to dump the memory could pull them out.
We need to distinguish between the server where EnvKey's API is running, which contains EnvKey's back-end logic, and 'client' servers (or user devices) that are connecting to EnvKey to fetch config for a particular app/environment. (It's possible I misunderstood the distinction the parent comment was getting at.)
EnvKey's API server has no access to secrets data. But you're right that a server pulling secrets via an ENVKEY access key would still have to expose those secrets in RAM to the process that needs them. We don't claim to protect user devices or connected servers from endpoint compromise.
We do offer some features to help mitigate this though:
- You can limit access to an ENVKEY to specific IPs or CIDR ranges.
- On a user device, secrets are periodically removed from RAM if they haven't been accessed recently.
- On a user device, only encrypted data is stored on disk, and the OS keychain is used on Mac and Windows.
- If an ENVKEY's access it cut off, envkey-source can immediately kill the process, making the secrets harder to access from RAM.
- Audit logs can help you track exactly what was exposed and when in the event of an incident.
- Access to secrets is 'pushed' as far down the stack as possible... so your secrets at least wouldn't be accessible in some cloud provider database--they would need to get access to the running process itself or the machine's RAM.
> - On a user device, secrets are periodically removed from RAM if they haven't been accessed recently.
I looked at the ruby sdk code and it doesn't periodically remove them from RAM. Storing the ENVs in the `ENV` object makes me nervous, because its an easy target for supply attacks to dump the `ENV` to logs / remote servers.
You're right--another distinction is needed here. For a human user using EnvKey, the EnvKey 'core-process' will run on their computer. Both the EnvKey UI and the CLI talk to this core process to fetch/display data or make updates. This is the process that will periodically evict secrets from RAM if they aren't used.
When loading a single environment via an ENVKEY access key, you're correct that there is no RAM eviction (in many cases this could break an app, unless it was designed to handle it).
If you don't want to use ENV/environment variables, you could also output your environment to a file and then pull it into your app and parse it (you can easily export to json, yaml, dotenv, or pam format):
Those cmds write the variables unencrypted to disk?
Looking at the ruby sdk, I don't see any decryption libraries being used. I'd imagine a more secure solution would be to give the sdk the decryption key when the variables need to be decrypted, they are only decrypted by the process in RAM.
Since its ruby, and everything has access to everything in the process, it might make more sense to key management to exist in another process (thus limiting what access simple supply chain attacks have access to).
Yes, those commands write the variables to a file, though you could also make a system call instead from within your app if you didn't want them in a file or environment variables.
The language SDKs (including ruby) wrap the envkey-source binary, which is where all the decryption and verification logic lives:
There is an -m/--mem-cache flag that you can pass to envkey-source that makes it work just as you're describing. It keeps the variables in RAM and listens for updates, keeping them all up-to-date.
True, but if the attack isn't targeted to the application, the attacker may naively just dump the `ENV` object instead of trying to it in the gem's memory space.