In addition to being able to store secrets, Vault can encrypt/decrypt data that is stored elsewhere. The primary use of this is to allow applications to encrypt their data while still storing it in their primary data store. Vault does not store the data.
The transit
secrets
engine handles
cryptographic functions on data-in-transit, and often referred to as Encryption
as a Service (EaaS). Both small amounts of arbitrary data, and large files such
as images, can be protected with the transit engine. This EaaS function can
augment or eliminate the need for Transparent Data Encryption (TDE) with
databases to encrypt the contents of a bucket, volume, and disk, etc.
»Encryption Key Rotation
One of the benefits of using the Vault EaaS is its ability to easily rotate the
encryption keys. Keys can be rotated manually by a human, or an automated
process which invokes the key rotation API endpoint through cron
, a CI
pipeline, a periodic Nomad batch job, Kubernetes Job, etc.
The goal of this tutorial is to demonstrate an example for re-wrapping data after rotating an encryption key in the transit engine in Vault.
»Personas
The end-to-end scenario described in this tutorial involves two personas:
- security engineer with privileged permissions to manage the encryption keys
- app with un-privileged permissions rewraps secrets via API
»Challenge
Vault maintains the versioned keyring and the operator can decide the minimum version allowed for decryption operations. When data is encrypted using Vault, the resulting ciphertext is prepended with the version of the key used to encrypt it.
The following example shows data that was encrypted using the fourth version of a particular encryption key:
For example, an organization could decide that a key should be rotated once a week, and that the minimum version allowed to decrypt records is the current version as well as the previous two versions. If the current version is five, then Vault would decrypt records that were sent to it with the following prefixes:
- vault:v5:lkjasfdlkjafdlkjsdflajsdf==
- vault:v4:asdfas9pirapirteradr33vvv==
- vault:v3:ouoiujarontoiue8987sdjf^1==
In this example, what would happen if you send Vault data that was encrypted
with the first or second version of the key (vault:v1:...
or vault:v2:...
)?
Vault would refuse to decrypt the data as the key used is less than the minimum key version allowed.
»Solution
Luckily, Vault provides an easy way of re-wrapping encrypted data when a key is rotated. Using the rewrap API endpoint, a non-privileged Vault entity can send data encrypted with an older version of the key to have it re-encrypted with the latest version. The application performing the re-wrapping never interacts with the decrypted data. The process of rotating the encryption key and rewrapping records could (and should) be completely automated. Records could be updated slowly over time to lessen database load, or all at once at the time of rotation. The exact implementation will depend heavily on the needs of each particular organization or application.
»Prerequisites
To perform the tasks described in this tutorial, you need to have a Vault environment. Refer to the Getting Started tutorial to install Vault. Make sure that your Vault server has been initialized and unsealed.
The following tools are required in order to successfully run the sample application provided in this tutorial:
Download the sample application code from vault-guides repository to perform the steps described in this tutorial.
Clone the vault-guides
repository.
Or download the repository:
This repository contains supporting content for all of the Vault learn tutorials. The content specific to this tutorial can be found within a sub-directory.
Go into the vault-guides/encryption/vault-transit-rewrap
directory.
Working directory: This tutorial assumes that the remainder of commands are executed within this directory.
»Policy requirements
Each persona require a different set of capabilities. These are expressed in policies. If you are not familiar with policies, complete the policies tutorial.
The security engineer tasks require these capabilities.
NOTE: For these tasks, you can use Vault's root
token. However, it is
recommended that root tokens are only used for enough initial setup or in
emergencies. As a best practice, use tokens with an appropriate set of policies
based on your role in the organization.
The app tasks require these capabilities.
»Step 1: Start MySQL database in Docker
The application requires a MySQL database. Docker provides a MySQL server image that satisfies the application's requirements
NOTE: For the demonstration, a MySQL database runs locally using Docker. However, these steps would work for an existing MySQL database by supplying the proper network information to your environment.
Pull a MySQL server image with docker
.
Create a directory for the demo data.
Create a database named my_app
that sets the root user password to root
and
adds a user named vault
.
The database is available.
»Step 2: Enable the transit secrets engine
(Persona: security engineer)
Enable the transit
secrets engine.
Create an encryption key to use for transit named my_app_key
.
The transit key my_app_key
is created.
»Step 3: Generate a new token for sample app
(Persona: security engineer)
Before generating a token, create a limited scope policy named rewrap_example
for the sample application.
Display the limited scope policy stored in rewrap_example.hcl
.
Create the rewrap_example
policy.
The policy is created.
Create a token with the rewrap_example
policy.
The output displays a token capable of using the transit key my_app_key
.
Create another token and store the token in the variable APP_TOKEN
.
Display the APP_TOKEN
.
The application uses this token to seed the database.
»Step 4: Run the sample application
(Persona: app)
The application stores data within the database. The data contains a field that require encryption. Vault provides that encryption through the transit secrets engine.
File | Description |
---|---|
Program.cs | Starting point of this sample app (the Main() method) is in this file. It reads the environment variable values, connects to Vault and the MySQL database. If the user_data table does not exist, it creates it. |
DBHelper.cs | Defines a method to create the user_data table if it does not exist. Finds and updates records that need to be rewrapped with the new key. |
AppDb.cs | Connects to the MySQL database. |
Record.cs | Sample data record template. |
VaultClient.cs | Defines methods necessary to rewrap transit data. |
WebHelper.cs | Helper code to seed the initial table schema. |
rewrap_example.csproj | Project file for this sample app. |
Run the sample application with the Vault server address, the transit key, and the generated token.
The application finishes after it generates several database entries.
Connect to the database with the root credentials.
Within the mysql shell, connect to the my_app
table.
Within the mysql shell, display 10 rows from the user_data
table where the
city starts with a Vault transit key.
The results display 10 rows that match this query. The city field is encrypted with the Vault transit key.
Drop the connection to the database.
The application used the Vault server through the application token to encrypt these fields.
»Step 5: Rotate the encryption key
(Persona: security engineer)
The encryption key my_app_key
can be rotated.
Rotate the my_app_key
transit key.
Display information about the my_app_key
transit key.
The output displays that this transit key has two versions.
»Step 6: Programmatically re-wrap the data
(Persona: app)
The application's database contains fields encrypted with the first version of the transit key.
Run the application again to re-wrap the encrypted fields.
The application finishes after it re-wraps the encrypted fields in the existing entries.
Connect to the database with the root credentials.
Within the mysql shell, connect to the my_app
table.
Within the mysql shell, display 10 rows from the user_data
table where the
city starts with a Vault transit key version v1
.
The results of this query are an empty set.
Within the mysql shell, display 10 rows from the user_data
table where the
city starts with a Vault transit key version v2
.
The results display 10 rows that match this query. The city field is encrypted with the second version of the Vault transit key.
Drop the connection to the database.
»Conclusion
An application similar to this could be scheduled via cron, run periodically as a Nomad batch job, or executed in a variety of other ways. You could also modify it to re-wrap a limited number of records at a time so as to not put undue strain on the database. The final implementation should be based upon the needs and design goals specific to each organization or application.