danielberkompas / cloak

Elixir encryption library designed for Ecto
MIT License
548 stars 55 forks source link

Provide Vault Transit cipher #21

Closed tlvenn closed 7 years ago

tlvenn commented 7 years ago

Thanks for this great lib Daniel !

I was thinking that it would be pretty awesome to provide a Vault Transit cipher: https://www.vaultproject.io/docs/secrets/transit/index.html

Benefits would be that the key is never touching the app, encryption/decryption happen within a pretty secure dedicated service. Transit support key rotation and rewrap.

tlvenn commented 7 years ago

Good intermediate solution would be to fetch the key(s) from Vault so that the encryption/decryption is still done by the app but the key is never stored in the config or exposed to the host as ENV variable.

danielberkompas commented 7 years ago

@tlvenn That could be pretty interesting. I assume that Vault is supposed to be used like an HSM: whenever you want data encrypted or decrypted, you ship it off to Vault and use the response.

A couple thoughts:

tlvenn commented 7 years ago

I assume that Vault is supposed to be used like an HSM

Not necessarily, actually in most cases, it's being used as a secure trusted credential store that apps interact with to get credentials, tokens, keys and the like. So it's not like an HSM in that regard.

The key idea is all your credentials are stored in a centralised secure store and those credentials are only maintained in memory by the services which need them.

The host knows how to fetch keys from Vault, which is pretty much the same thing as storing them in environment variables. It's just a layer of indirection

Yes but it's all in memory and should a given host be taken over, it's not immediately obvious how to retrieve such key and more importantly, because the key is not on the disk, by revoking the token that the host use to interact with Vault, you essentially cut off the hacker from retrieving the key all together if you detect the hack in time. If the key is on the host, as soon as the host is taken over, it's essentially game over already.

Also beyond the security aspect alone, not having to deal with how will have to expose that key as an ENV prop to your runtime in a somewhat secure way is a big plus. Much easier to let the app pull the secret instead of figuring out how to push the secret to it.

Doing a network roundtrip to Vault adds latency, the possibility of network failure, (causing Ecto.Type cast errors?) and possibly exposes your plaintext to interception in transit. Technically, it wouldn't be too hard to implement as an Ecto.Type though. I might play around with this.

Yes leveraging the vault transit backend is challenging and cant be used in situation where you need to keep the latency as low as possible. I guess that would be an acceptable tradeoff for use cases that would require a more secure solution where no secret from Vault transit on the apps at all, essentially treating Vault as a blackbox security module.

danielberkompas commented 7 years ago

@tlvenn So, as I understand it, the idea here would be to create a cipher which:

  1. Stores a token/url to communicate with Vault
  2. On encrypt/decrypt, fetches the key from Vault using this token, and then performs the operation locally.
tlvenn commented 7 years ago

Hi @danielberkompas,

I would configure the host/port/path/token used by Cloak to interact with Vault using (:cloak, :vault, ...) at the app level.

Then I would leverage the generic backend and dedicate a path/namespace to cloak (/secret/cloak for example)

https://www.vaultproject.io/docs/secrets/generic/index.html

Under that namespace we can store different versions of the key and the token provided to the app would allow to read only those keys under the defined namespace. A simple CLI(exposed as mix task?) could be provided to rotate the key and you would have to provide the cli a token that can actually write to the namespace.

On the app side, I would cache the keys that are fetched already from Vault in an ETS table and probably keep them in the ETS table encrypted using a generated key when cloak is started so that you cant simply introspect the ETS table and get the keys at runtime.

What do you think ?

tlvenn commented 7 years ago

Regarding the CLI, vault has a CLI already so I think it should be enough to simply generate the vault cli command needed to init clock or rotate the key.

tlvenn commented 7 years ago

Hi @danielberkompas,

Was thinking about this more and actually we dont really need to do anything on Cloak side unless we decide to leverage the Vault Transit backend. The idea would be to simply create a VaultConfig lib which can pull secrets from Vault and inject it into the application env.

Then it only a matters of making sure that the keys cloak expects are loading by VaultConfig.

danielberkompas commented 7 years ago

Yeah, that makes sense! I'll close this issue down then. Thanks for your attention to this!