Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asymmetric encryption of request bodies [happy to build this] #7639

Open
jackkleeman opened this issue Oct 13, 2019 · 5 comments
Open

Asymmetric encryption of request bodies [happy to build this] #7639

jackkleeman opened this issue Oct 13, 2019 · 5 comments

Comments

@jackkleeman
Copy link
Contributor

Is your feature request related to a problem? Please describe.
One thing that we have found challenging with Vault is getting key material from an airgapped laptop (where we generate the material) to Vault without it passing through an unsafe device. The solution we have come to is a Vault plugin from which we obtain a public key, then pass encrypted KV secrets to, along with a path, and a Vault token, at which point the Vault plugin decrypts the secrets and posts them to Vault at that path. We would love to be able to do this in a generic way, ie not just for KV secrets, and without the need for a plugin!

Describe the solution you'd like
I would love to be able to ask Vault for a public key, encrypt whatever json body I would otherwise send with that key (perhaps with some nice sugar in the Vault cli which works offline), and have any Vault endpoint (including plugins) be able to understand this encrypted body and transparently pass it into the underlying Vault endpoint. Essentially the decryption would have to happen at buildLogicalRequest stage.

There are a few approaches to the encryption; we could simply asymmetrically encrypt the entire body to an RSA/elliptic key (simplicity is nice), or we could AES encrypt it to a random key and send that (more efficient for large bodies, I guess), or we could optionally AES encrypt individual fields (would allow people to add additional fields after the airgapped generation stage).

Describe alternatives you've considered
We could expand our Vault plugin to handle more types of requests beyond KV, and maybe open source it too. But I don't feel good about passing tokens into a plugin so that it can do things on my behalf, and I don't like that the plugin is making requests to the Vault API. This feels like an abuse of plugins.

We are of course aware that many types of key can be generated inside Vault, but when working with finance stuff as we do at Monzo, you get some weird crypto where that isn't really an option.

Explain any additional use-cases
I think the key use case is generation of request bodies on secure laptops. You could also have the Vault CLI use encrypted requests for online API calls, for defence in depth (but as there's no proper key negotiation, its not much of a defence).

Additional context
I'm very happy to build this, by the way, this issue is to find out whether Vault would accept the change, and how the maintainers would prefer it was implemented.

@jefferai
Copy link
Member

We've actually been wanting to build this forever. One of the original use cases with the Identity system when thinking about it before 0.8 was for exactly this: that since you wouldn't have to define keys per token but rather have tokens associated with an entity in Identity that you could then put a public key there and actually have it usable. We didn't build it because we had no real demand from users and customers (until now!).

@amanoske I know we talked about this forever ago, you still into it?

Two things I'll say up front: if the team wants to include this don't build it without working on the design with us (I can't commit their time); the other is it should use symmetric encryption, e.g. an exchange of curve25519 public keys to derive a shared key. No RSA these days. :-)

@jackkleeman
Copy link
Contributor Author

jackkleeman commented Oct 13, 2019

the other is it should use symmetric encryption, e.g. an exchange of curve25519 public keys to derive a shared key

What options are available for this that wouldn't require some communication between the airgapped machine and Vault? Sharing public keys beforehand is okay as they persist, but if I have to transport something between the laptop and Vault each time we do an exchange, that isn't ideal. Is it so painful to just encrypt to a 25519 public key directly? I don't think authentication of the sender is required given we will also have a Vault token

if the team wants to include this don't build it without working on the design with us

Yep fair enough, let's do it! I appreciate you may have time constraints

@jefferai
Copy link
Member

Is it so painful to just encrypt to a 25519 public key directly?

In that they don't support encryption, yes :-)

But you don't need to transfer over and over. You're thinking of curve25519 as it's classically used, to protect ephemeral symmetric keys. But in that scenario you're generating a new public/private key pair for each conversation, because the same set of public/private keys maps to the same symmetric key. If you re-use the same key pair, the symmetric key is simply not ephemeral. So instead of using the key directly, you are just re-multiplying the public and private keys together to get the shared key and using that. In that way it works much like PGP.

@jefferai
Copy link
Member

Oh one thing to point out about that scheme is unlike the RSA case the client must also be able to store a private key, to compute the shared secret. The problem is that RSA is more or less deprecated at this point by NIST as it's entirely quantum-unsafe.

Normally I'd say you could store this private key in Vault, using Identity to gate access to it, but the point for you is that the laptop is airgapped. That said, you're getting a token to it, so the process of getting a token to it could be accompanied by also passing it a value read out of K/V (or, decrypted via transit).

Another approach might be if you could store the private key within Vault as well, and Vault could distribute it at authentication time along with a token when it distributes other Identity information. This means that a lay token can't be used to discover the private key, but if you have just proved your authentication to Vault and Vault is granting you an access token then you are already making a pretty high-trust call.

All that said, one of the benefits of the fact that it's a symmetric key actually is that you can prevent token information from going out over the wire in plaintext, because once the client's public key is registered, any response could in theory also be encrypted (regardless of the TLS on the outside). So it's not just your requests going through various machines that are protected, but the responses too.

@jackkleeman
Copy link
Contributor Author

jackkleeman commented Oct 27, 2019

I think I was interpreting what you were saying as something more like ephemeral diffie hellman but I realise now you can do a static-static approach. If its a shared key based on the partners public key only, that sounds better. I'm not completely averse to the airgapped laptop having some kind of persistent identity, although I think we had intended to start wiping these laptops on every use.

It's cool to encrypt the response too, although I suspect for most use cases with an airgapped laptop (injection of some kind) you won't need a response necessarily and it might be more convenient to have it be readable on the online machine.

That said, you're getting a token to it

Actually, we aren't, we are taking the encrypted request body from the laptop and sending that along with a token. I guess in my head, the solution here would be an encrypted body, but headers including token unaffected - you can set these on an online machine.

I think if the encryption of the injected material is backed by a private key, that private key needs to be generated offline too and never touch an online laptop. So I don't think we could store it in Vault, but that's not the end of the world I guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants