We’ve already seen the transit secrets engine in one of the previous posts in this series, but we will revisit the topic in this post.
The transit secrets engine handles encryption on data in-transit. No data handled by this secrets engine is persisted to storage in Vault. Apart from encrypting and decrypting data the transit engine can also sign and verify data, generate random bytes, and more.
There are several key types (or encryption algorithms) supported by the transit secrets engine: aes128-gcm96
, aes256-gcm96
, chacha20-poly1305
, ed25519
, ecdsa-p256
, ecdsa-p384
, ecdsa-p521
, rsa-2048
, rsa-3072
, rsa-4096
, and hmac
.
Explaining encryption as a service make up the tenth and last objective in the Vault certification journey. This objective covers the following sub-objectives:
Configure transit secret engine#
To start off we should enable the transit secrets engine on our Vault server. We’ve seen how to enable secrets engines before:
$ vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/
The main use-case for the transit secrets engine is to encrypt and decrypt data, thus we will create a key to do just that. To create a key we run the following command:
$ vault write -f transit/keys/demo-key \
type=rsa-4096 \
auto_rotate_period=1h
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 1h
deletion_allowed false
derived false
exportable false
imported_key false
keys map[1:map[creation_time:2023-09-15T17:47:46.020802+02:00 name:rsa-4096 public_key:-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqF4TxwdIpmVcXTri+Y1a
MGL7fM2xUeGDpDMfxnR1gJwjhda2zFud07TZ9RwmeFgxnbj9VwYRu9ThL1tAZ+32
72nZjizb2rJWp0UUYSWk5BcgUCa1NPM7gTcrgp9INXidHeTnC5TxUC4N2alUoPsG
r5opxHEVrBWQZxRx6AuOnP6YzmQSJMS4pv+0cH+dP0HUj1X2Kso3OuFNFSplsSPm
I9bZxOazmPNz9x4MYRfp3a5EOp6FmE/EKd2kOZ6EYaD0R+oNsI1lg79lpsDckIHY
ISFZd9sM5xVZTrXhBng2MMfpWwjSqoaJVeycQ91RYr3KzkmUW5UrXN3ksq/ncLBM
SXOcfhFgkLAXUbsEaMQE08ug4J+hEJj5Jh9By9DlNS2UMASySAwuUTJ1c78SE3fs
1YGaxZkt88mEuLOY0wUD0/0gEMshn/Lh3pjJvlYxMtwsdtVMx/zUsdaa6ialAFFl
6aKMCnvaQHtwS3O3oPma6c/qX714AKGmceZswxp8IhErafG0Wca7/JHTrUQNasWZ
HzDFqS2S5F1bu7oKICl+JELnpHu570MjtYXAomw3EHqNvPvw72ihdZ5tBX/QH1l1
iwIv+a76bfM3F5myoPP5uzNk6fPt73u0zLCKYfVK4fvr/V8CtCML6foUFtXGn9OQ
0vS2bGk64K2fTNfcSbC+P6kCAwEAAQ==
-----END PUBLIC KEY-----
]]
latest_version 1
min_available_version 0
min_decryption_version 1
min_encryption_version 0
name demo-key
supports_decryption true
supports_derivation false
supports_encryption true
supports_signing true
type rsa-4096
In the previous command I specified that the key type should be rsa-4096
and I want the key to automatically rotate every hour. To see all the available configuration options when creating a key see the API documentation.
Encrypt and decrypt secrets#
In this section I continue where I ended the last section. The status is that we have a key named demo-key
. We could read information about our key using vault read transit/keys/demo-key
.
Now I want to encrypt some data using my new key. Remember from earlier posts that the data I want to encrypt must be base64-encoded:
$ vault write transit/encrypt/demo-key plaintext=$(echo "s3cr3tm3ss4g3" | base64)
Key Value
--- -----
ciphertext vault:v1:N+bgVOhRl5xrwcZ7Aovlg2CF9I+sB9eHt8Yspxw0CrGnR/llTp+9KPZjrA8ou2pznNZ20RdVI291TB2e3jKNLVR36pPQ8iEwfm4HNv+TVS+KJl0CvCweBGa84RrDeIUauwSgHx4vWV2SSz6qJSV8qBrwXKRSq6GPWS4bAu6U9+H2Yq6Zpvr3/mpSX1oZz4HL1PP/zds0taYNWaRJBUr9TDbgRQVto57Swy408+x1Fn9tq670go/ghYbXBV5idL+8O5IndKVB5xukwXNVvrXI4fO/lMBBkSfnGsqWUiACqCzYRPABEN2MHI6Zgfjdfi3CEr2XNCMf/dqEyK01WC9S0ERJM064dT+5oCUQzsll8e0dOGSkbFrKfTGWZExMBHrSHDrGREUEf1h/fT4gNf0udg9V5SUt+dniVkKWXQt6JqUhwIMzEglkJmsmrPDOQxXt9nziiO3mUvI1f2d99nYDicdFgCBULP9jQ7EpLM8V0NC1F/J+Rqk663ZHHZrHotfK9hDk54wfWzTfqKj+XYtqmr5SneRePOyCCtB1bOSkulgrPJQpkvrWowMCGz5eiaTrbGZjPORnkYdX8nEqv3kGIrDR6ZiP+HANzU9/BQBalr05A+UWY8XMa/4P9nPCH7cnah/vZxDicvkEF8ROxoslVfZcPPhQwxSCeRwRdX7kDK4=
key_version 1
To get my data back again I can do so using the following command:
$ vault write transit/decrypt/demo-key \
ciphertext=vault:v1:N+bgVOhRl5xrwcZ7Aovlg2CF9I+sB9eHt8Yspxw0CrGnR/llTp+9KPZjrA8ou2pznNZ20RdVI291TB2e3jKNLVR36pPQ8iEwfm4HNv+TVS+KJl0CvCweBGa84RrDeIUauwSgHx4vWV2SSz6qJSV8qBrwXKRSq6GPWS4bAu6U9+H2Yq6Zpvr3/mpSX1oZz4HL1PP/zds0taYNWaRJBUr9TDbgRQVto57Swy408+x1Fn9tq670go/ghYbXBV5idL+8O5IndKVB5xukwXNVvrXI4fO/lMBBkSfnGsqWUiACqCzYRPABEN2MHI6Zgfjdfi3CEr2XNCMf/dqEyK01WC9S0ERJM064dT+5oCUQzsll8e0dOGSkbFrKfTGWZExMBHrSHDrGREUEf1h/fT4gNf0udg9V5SUt+dniVkKWXQt6JqUhwIMzEglkJmsmrPDOQxXt9nziiO3mUvI1f2d99nYDicdFgCBULP9jQ7EpLM8V0NC1F/J+Rqk663ZHHZrHotfK9hDk54wfWzTfqKj+XYtqmr5SneRePOyCCtB1bOSkulgrPJQpkvrWowMCGz5eiaTrbGZjPORnkYdX8nEqv3kGIrDR6ZiP+HANzU9/BQBalr05A+UWY8XMa/4P9nPCH7cnah/vZxDicvkEF8ROxoslVfZcPPhQwxSCeRwRdX7kDK4=
Key Value
--- -----
plaintext czNjcjN0bTNzczRnMwo=
I get the base64-encoded value back, which I can decode to my secret:
$ echo "czNjcjN0bTNzczRnMwo=" | base64 -D
s3cr3tm3ss4g3
Rotate the encryption key#
When we encrypted data in the previous section the resulting ciphertext was prepended with vault:v1
. This tells us that the data has been encrypted by the transit secrets engine in Vault and the key version uses was v1
. What happens if we rotate our key and get a new version of it?
Let’s do just that. I can rotate my key using the following command:
$ vault write -f transit/keys/demo-key/rotate
Key Value
--- -----
allow_plaintext_backup false
auto_rotate_period 1h
deletion_allowed false
derived false
exportable false
imported_key false
keys map[1:map[creation_time:2023-09-15T17:47:46.020802+02:00 name:rsa-4096 public_key:-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqF4TxwdIpmVcXTri+Y1a
MGL7fM2xUeGDpDMfxnR1gJwjhda2zFud07TZ9RwmeFgxnbj9VwYRu9ThL1tAZ+32
72nZjizb2rJWp0UUYSWk5BcgUCa1NPM7gTcrgp9INXidHeTnC5TxUC4N2alUoPsG
r5opxHEVrBWQZxRx6AuOnP6YzmQSJMS4pv+0cH+dP0HUj1X2Kso3OuFNFSplsSPm
I9bZxOazmPNz9x4MYRfp3a5EOp6FmE/EKd2kOZ6EYaD0R+oNsI1lg79lpsDckIHY
ISFZd9sM5xVZTrXhBng2MMfpWwjSqoaJVeycQ91RYr3KzkmUW5UrXN3ksq/ncLBM
SXOcfhFgkLAXUbsEaMQE08ug4J+hEJj5Jh9By9DlNS2UMASySAwuUTJ1c78SE3fs
1YGaxZkt88mEuLOY0wUD0/0gEMshn/Lh3pjJvlYxMtwsdtVMx/zUsdaa6ialAFFl
6aKMCnvaQHtwS3O3oPma6c/qX714AKGmceZswxp8IhErafG0Wca7/JHTrUQNasWZ
HzDFqS2S5F1bu7oKICl+JELnpHu570MjtYXAomw3EHqNvPvw72ihdZ5tBX/QH1l1
iwIv+a76bfM3F5myoPP5uzNk6fPt73u0zLCKYfVK4fvr/V8CtCML6foUFtXGn9OQ
0vS2bGk64K2fTNfcSbC+P6kCAwEAAQ==
-----END PUBLIC KEY-----
] 2:map[creation_time:2023-09-15T18:00:01.621354+02:00 name:rsa-4096 public_key:-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAymFiLHw/G5jZN+xtEBlb
ILhBMmn8F0CchTbKjr/cm8n5vus1OonamkuWY9Zk23al9Rf9mOYg2ZP453fJ8W0z
ZrrUJQxGsEV0T2xmjab5Xk7nUh2cDwhHGZu1t27z0up3F5XKezknokyB+EPAH33H
UrUB/AHMDGRcR0Gb0qNum0k6N2w9Y4iUO9Hq9UjnkpqoqAqY6CFScdl+QKu+kYj3
AlucROc0wR4XhhxAvl6CX25g/0kmonUjLZFylilS6qzqVQMcg7jgHqC8JwJ0S9Ds
RZr65IV4YLw5xBzZhooLEUT8E/8pIZxwJ3UmrR5EZkjkewU+D8YVJ5qYM7S785Cu
kKWB1QwGZ4Bmoue4n3Nw7y5YPGpv4KUrTB8/Kusl420LcgCRA3zENIV9zg+QAoPb
b7JJ4TV3P18uxfbNYn6v/N/GKjaCWYtCMGEKAjhzNZkvtmbGK3zZoE+HhvKb3Z7y
2D5ARe1Hu2e+z9r0PL+LH8ELQT+9kExwVBoMrxcNJq1fPtWSj2szGcq2YJMip91g
G7HQ2p28MVMkkFHSPUsDLPnBcpVs0lOb8mjwU+zeHGTTigH79R3XXsxZ0gwbSPxH
VeFcv3tFAPcQ+suyM2kpwrfFzvGopJSZuL/oUoqMHKdzrSbQy/c2t4W5pVUoHXga
2iEE0ALm/6V1W/3eqP2AIAMCAwEAAQ==
-----END PUBLIC KEY-----
]]
latest_version 2
min_available_version 0
min_decryption_version 1
min_encryption_version 0
name demo-key
supports_decryption true
supports_derivation false
supports_encryption true
supports_signing true
type rsa-4096
The metadata in the output says that latest_version
is now 2
. However, min_decryption_version
is 1
which means that even if some ciphertext is encrypted using version one of our key it will still be possible for us to decrypt the value. You can configure what the min_decryption_version
should be. Perhaps you don’t want to allow any other key than version two to be able to decrypt values, then you can configure this.
Something else you might want to do is to re-encrypt your data with the latest version of the key. You can do this without exposing the secret data at any stage. To do this run the following command together with the ciphertext from before:
$ vault write transit/rewrap/demo-key \
ciphertext=vault:v1:N+bgVOhRl5xrwcZ7Aovlg2CF9I+sB9eHt8Yspxw0CrGnR/llTp+9KPZjrA8ou2pznNZ20RdVI291TB2e3jKNLVR36pPQ8iEwfm4HNv+TVS+KJl0CvCweBGa84RrDeIUauwSgHx4vWV2SSz6qJSV8qBrwXKRSq6GPWS4bAu6U9+H2Yq6Zpvr3/mpSX1oZz4HL1PP/zds0taYNWaRJBUr9TDbgRQVto57Swy408+x1Fn9tq670go/ghYbXBV5idL+8O5IndKVB5xukwXNVvrXI4fO/lMBBkSfnGsqWUiACqCzYRPABEN2MHI6Zgfjdfi3CEr2XNCMf/dqEyK01WC9S0ERJM064dT+5oCUQzsll8e0dOGSkbFrKfTGWZExMBHrSHDrGREUEf1h/fT4gNf0udg9V5SUt+dniVkKWXQt6JqUhwIMzEglkJmsmrPDOQxXt9nziiO3mUvI1f2d99nYDicdFgCBULP9jQ7EpLM8V0NC1F/J+Rqk663ZHHZrHotfK9hDk54wfWzTfqKj+XYtqmr5SneRePOyCCtB1bOSkulgrPJQpkvrWowMCGz5eiaTrbGZjPORnkYdX8nEqv3kGIrDR6ZiP+HANzU9/BQBalr05A+UWY8XMa/4P9nPCH7cnah/vZxDicvkEF8ROxoslVfZcPPhQwxSCeRwRdX7kDK4=
Key Value
--- -----
ciphertext vault:v2:aEu3sdXwj3Wp1gcu3YEwqnQ4iINzH8ZBqzpUZFuLFJjxIGHEs0W9nbeRFdn3ertys6M0yR6D+gOrl+te2tqXuwVmvmbskT9shQYFPzjVfI4L6DpjNWpOvGqXb2A+GS86UJIxwNK/5Y/S+WizSFnQ7BXpMunKvan6lIP0SPSfqfCYzWuqcWfKkftTnzLiddWYxKk8AJHd2B3z+ahSM9pkAtjmxm7I6+SCwJ+VcJRR1UMpz/4/Z9QDgzU2xEMV1Nk3VMdUppJseavXzdl98zkB6X4ulOj9zMDMLwJHpLCVTjnrENhrui4sLWqZAhzTFI5joydpqzSC3mGwHaxrMyGqJ/CQS5WivU05euiQC+QyyziPPoff1ltmgt+OkQoKzjZfgG9Vy/B2wz71NqmFY/zpF+XNrkUVs9G7TlUFCZXwwL0mqzCitUPmP8UllnWVx+s9XoZ3dtdvwHtMPoSlUmjMeftZmxUJXglA6YZXvsI1vhDY7jpornJmlwz2a2L0HsK0zVFGwJE7DKAFBeR85U7XQZmXl+CYS0WE/Mm3VycwQWdxfUpAz7niYz3bfKbSIGJ5b/fsMvHvDQc4nPszdVMqEe5NV6RPFlR0APfl/ys64Izl+GLagitrMzc89PJzj8Y/Z6umz/29hkBb8uom6YTf3cgHLIQEC4HTCV7KZ7wTGzA=
key_version 2
The new ciphertext is prepended with vault:v2
which indicates that it is now encrypted with the latest version of the key. Let’s verify that we can still decrypt the data:
$ vault write transit/decrypt/demo-key \
ciphertext=vault:v2:aEu3sdXwj3Wp1gcu3YEwqnQ4iINzH8ZBqzpUZFuLFJjxIGHEs0W9nbeRFdn3ertys6M0yR6D+gOrl+te2tqXuwVmvmbskT9shQYFPzjVfI4L6DpjNWpOvGqXb2A+GS86UJIxwNK/5Y/S+WizSFnQ7BXpMunKvan6lIP0SPSfqfCYzWuqcWfKkftTnzLiddWYxKk8AJHd2B3z+ahSM9pkAtjmxm7I6+SCwJ+VcJRR1UMpz/4/Z9QDgzU2xEMV1Nk3VMdUppJseavXzdl98zkB6X4ulOj9zMDMLwJHpLCVTjnrENhrui4sLWqZAhzTFI5joydpqzSC3mGwHaxrMyGqJ/CQS5WivU05euiQC+QyyziPPoff1ltmgt+OkQoKzjZfgG9Vy/B2wz71NqmFY/zpF+XNrkUVs9G7TlUFCZXwwL0mqzCitUPmP8UllnWVx+s9XoZ3dtdvwHtMPoSlUmjMeftZmxUJXglA6YZXvsI1vhDY7jpornJmlwz2a2L0HsK0zVFGwJE7DKAFBeR85U7XQZmXl+CYS0WE/Mm3VycwQWdxfUpAz7niYz3bfKbSIGJ5b/fsMvHvDQc4nPszdVMqEe5NV6RPFlR0APfl/ys64Izl+GLagitrMzc89PJzj8Y/Z6umz/29hkBb8uom6YTf3cgHLIQEC4HTCV7KZ7wTGzA=
Key Value
--- -----
plaintext czNjcjN0bTNzczRnMwo=
And we must remember to decode the base64-encoded value:
$ echo "czNjcjN0bTNzczRnMwo=" | base64 -D
s3cr3tm3ss4g3