Skip to main content

Seal Wrapping with HashiCorp Vault and CloudHSM


HashiCorp Vault provides a way to securely store static secrets and generate dynamic ones. For both types, operators of Vault will need to store data whether it is static passwords or cloud credentials to allow Vault to provision dynamic ones for future clients. In most cases, Vault’s method of encrypting data with its AES-256 encryption key is enough to satisfy security needs but in some cases, there is a higher standard of encryption that must be met. Occasionally, Vault needs to be held to higher standards, such as the standards set by FIPS’ security standards; this is where the integration with an HSM comes in. An HSM can integrate with Vault to become its seal so that it is able to provide auto-unseal capabilities by encrypting Vault’s master key with its own encryption key. Most vault users are likely used to using the default Shamir method where Vault splits off its master key into shards.

Auto-unsealing provides a streamlined approach to ensuring your Vault cluster stays online but it doesn’t provide any extra encryption to your data that is stored in Vault. This is where Seal Wrapping comes in. Seal Wrapping provides the conformance with the FIPS 140-2 standard and provides additional encryption by not only encrypting data with Vault’s encryption key but to also encrypting it through the HSM.

For this blog, I set up an HSM and a Vault server to have a look at what data looks like when it is encrypted with and without Seal Wrapping.


To follow along with this blog, you will need:
An AWS account: Needed to deploy the CloudHSM and EC2 instance that will run Vault
A deployed CloudHSM: This blog does not cover how to deploy and configure CloudHSM but the Terraform code to deploy everything can be found here.
HashiCorp Vault running on an EC2 instance: This blog assumes you already have Vault running on an EC2 instance that is in a Security Group to connect to CloudHSM.

Everything you need to set the same lab environment up is available in the above repository. To easily deploy a Vault server on the EC2 instance you can use the Ansible role highlighted in the repository.

Vault’s Configuration

Vault leverages PKCS#11 authentication to connect to an HSM. To set this, Vault has a dedicated Seal stanza that allows users to provide information about the HSM connection, such as PIN and Slot, as well as the path to the crypto library. With that said, your Vault config should have a similar Seal stanza to the one below:

seal "pkcs11" { 
  lib            = "/opt/cloudhsm/lib/"
  slot           = "1"
  pin            = "vault_user:vaultarctiq"
  generate_key   = "true"
  key_label      = "vault"
  hmac_key_label = "vault"

Adding the above Seal stanza will tell Vault to do two things by default. The first is to leverage the HSM for auto-unsealing. Again, this process takes Vault’s master key and encrypts it with a key that lives in the HSM as opposed to splitting up the master key into chards, as done with Shamir. The second thing that the Seal stanza does, by default, is “wrap” a list of secrets and paths in Vault including, but not limited to, the Keyring, Master key, and Recovery key. A full list can be found here. On top of that list, Vault can also Seal Wrap specific Secrets Engines to further encrypt static data that is stored in Vault’s storage backend. The supported Secrets Engines and paths can also be found in that document.

Testing Seal Wrap

To see Seal Wrap in action, I’m going to use a file type storage backend so that I can actually traverse the directories where Vault stores its data and look at the cipher text to confirm Seal Wrap is working. I’m going to use the PKI Secrets Engine for my testing and show the difference between a wrapped and unwrapped version of that engine. The following steps will go through enabling PKI at two different mount points, uploading a CA cert and private key, and then verify the data has been stored.

# enable the PKI secrets engine without Seal Wrap
$ vault secrets enable -path=pki-unwrapped pki 

# enable the PKI secrets engine with Seal Wrap
$ vault secrets enable -path=pki-wrapped -seal-wrap pki

# list secrets engines that are enabled
$ vault secrets list -detailed

# write a CA bundle to the unwrapped PKI
$ vault write pki-unwrapped/config/ca [email protected]

# write a CA bundle to the wrapped PKI
$ vault write pki-wrapped/config/ca [email protected]

# look at how Vault has encrypted the unwrapped PKI data
$ cat /opt/vault/data/logical/4ac1d884-5a27-1e56-9af2-754822e9f84a/config/_ca_bundle

# look at how Vault has encrypted and wrapped the wrapped PKI data
$ cat /opt/vault/data/logical/80c2380b-a2db-0f37-804d-11964201088c/config/_ca_bundle

Looking closely at the values in the last two outputs, you will see a slight difference. The first output shows the truncated secret encrypted with Vault’s encryption key which is a standard across anything that passes Vault’s barrier and is stored in its storage backend. Looking at the second output, the value looks different, as expected. This is because Vault has applied a Seal Wrap to it, which means that it was both encrypted by Vault and encrypted by the HSM before being stored in Vault’s storage backend.


With Vault’s integration with an HSM, it has become a tool that can be brought into the conversation in even the most highly secure environments where standards set out by FIPS must be met. Operators of Vault can now guarantee data is completely encrypted by Vault and the HSM that it is connected to. These operators can now also leverage auto-unsealing to provide easier management in the event Vault is sealed due to a server failure or restart. If you are interested in learning more about how Vault works with HSMs, I encourage you to deploy the lab in the repo above and poke around Vault’s storage. You can also learn a bit more about how and where Vault stores specific pieces of data.

Share this story

Arctiq Team

We service innovation.