Encryption as a Service with Vault
Every developer has used encryption at some point and while easy to use, security is a major issue. You need those keys safe. You could of course stuff your keys in Vault key-value secrets engine but why manage keys at all. Let Vault handle it with the Transit Engine.
What transit engine does is, it provides encryption as a service so you don’t have to deal with or know encryption features and requirements.
What we need
- Vault, somewhere (I’m using local)
- Postman to send service requests if you want, bash is fine
Goal: Transfer encryption responsibilities to Vault and encrypt regular data without having any keys within our host.
The short version: Your app sends data it wants encrypted to Vault Transit Engine. Vault then encrypts and sends a cipher text of your data back to your app. The app can then store this encrypted data in any environment and send the cipher text back to Vault again to receive decrypted version.
Think of a case like this. You have sensitive data fields like accounts, private case details and such. These fields must be encrypted on the storage whether its db or anywhere else. You can manage access to these resources but generally storage and db (let’s call all of it storage from now on) are managed by another team and may be out of your control. Additionally, while there are other encryption tools available, you will just be adding more people and more tools to the equation, increasing the risk. When we add Vault to this equation, we just need a single tool to manage both our secrets and encryption capabilities. Vault does not hold anything we encrypt using the transit engine.
Let’s see the usage in example. Enable a transit engine like below;
I’m intentionally changing engine root directory so we don’t mistake it in commands. For the next part, we need to create an encryption key;
After the key creation, check out the options we can now perform.
From the UI, we can make basic tests. Write random things in the encrypt plain text field and click encrypt.
You will get a cipher text like below. This is the data that needs to be stored and will use this to convert it back to the original data.
Now going back to the transit engine and selecting decrypt tab, we can place the above cipher text and click decrypt.
Same operation can be done from the cli as well. We need to use base64 for the plaintext field which is the same as the previous example (test encrypt data)
vault write transittest/encrypt/my-super-secret-encyrption-key plaintext="dGVzdCBlbmNyeXB0IGRhdGE="
Using the ciphertext to decyrpt we get the same base64 we sent.
vault write transittest/decrypt/my-super-secret-encyrption-key ciphertext="vault:v1:X0B3STGriYAH7f/xVJQ18hu/Uhp4DMVE8+DvxEP/xldzRvEXVuDA8XI7/0gJ"
One thing to mention is the key we created for encryption operations needs to be protected otherwise everything encrypted by the transit engine can be decrypted.
To this end, instead of flinging the main data key around, we can generate a key for apps to own and use to encrypt, decrypt their data (using Vault still). This applies specifically for large data that needs to be encrypted as well. Instead of sending and receiving large chunks of data, apps can manage their own encryption with keys provided from Vault. They could be rotated daily to minimize risk and source would still be Vault.
Let’s create a key from our current key as below;
We can now encrypt data using the key in the Plaintext field and delete that key after we are done. But we need to save the cipherText when we want to decrypt since it contains our key in encrypted format. Using decrypt again we can reach the generated key.
As best practice, we can store the ciphertext for our key in the kv store.
So far we have been using a single key to encrypt/decrypt everything. Well, transit engine supports key rotation, versioned keys and minimum key version for decryption,
In all of our encrypt operations we received a cipher text like below so far
The v1 here is the version of our key. We can rotate it to create a new key as below;
Selecting edit, we can choose the minimum versions to decrypt and encrypt. Below I changed to min decrypt version to 2.
Also notice the Allow deletion checkbox. It’s false by default because if you delete a key, encrypted data cannot be decrypted anymore so it’s a matter to think about.
Get a ciphertext you have belonging to v1 and try to decrypt it now.
In case of emergency, the min decrypt version can be moved to allow this data to be decrypted as well.
One nifty thing Vault does for situations regarding data encrypted with old key versions is, it can rewrap the encryption with the current version.
Of course, we need to allow v1 we disabled previously for this operation to work,
Thanks for reading and see you next time.