open-vault/website/content/docs/secrets/transit/key-wrapping-guide.mdx
2022-09-06 10:52:02 -05:00

166 lines
5.4 KiB
Plaintext

---
layout: docs
page_title: Key Wrapping for Transit Key Import - Transit - Secrets Engines
description: |-
Details about wrapping keys for import into the transit secrets engine.
---
# Key Wrapping for Transit Key Import
The "bring your own key" (BYOK) functionality for the transit
secrets engine allows users to import keys that were generated
outside of Vault into the transit secrets engine.
This document describes the process for wrapping an externally-generated
key (the target key) for import into Vault. It describes the processes
for importing a software-stored key using Golang and for importing a key
that is stored in an HSM.
### Mount the secrets engine
```shell-session
$ vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/
```
### Retrieve the transit wrapping key
```shell-session
$ vault read transit/wrapping_key
```
This returns a 4096-bit RSA key.
The steps after this depend on whether the key is stored using
a software solution or in an HSM.
### Software Example (Go)
This example assumes that the key is stored in software using the
variable name `key`. It demonstrates how to wrap the target key using
Golang crypto libraries.
Once you have the wrapping key, you can parse it using the `encoding/pem`
and `crypto/x509` libraries (the example code below assumes that the wrapping
key has been written to a variable called `wrappingKeyString`):
```
keyBlock, _ := pem.Decode([]byte(wrappingKeyString))
parsedKey, err := x509.ParsePKIXPublicKey(keyBlock.Bytes)
if err != nil {
return err
}
```
Then generate an ephemeral AES key for wrapping the target key.
This example uses Golang's `crypto/rand` library for generating the key:
```
ephemeralAESKey := make([]byte, 32)
_, err := rand.Read(ephemeralAESKey)
if err != nil {
return err
}
```
~> **NOTE**: Be sure to securely delete the ephemeral AES key once it
has been used!
Google's [tink library](https://pkg.go.dev/github.com/google/tink/go@v1.6.1/kwp/subtle)
provides a function for performing the key wrap operation:
```
wrapKWP, err := subtle.NewKWP(aesKey)
if err != nil {
return err
}
wrappedTargetKey, err := wrapKWP.Wrap(key)
if err != nil {
return err
}
```
Then encrypt the ephemeral AES key using the transit wrapping key:
```
wrappedAESKey, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
wrappingKey,
ephemeralAESKey,
[]byte{},
)
if err != nil {
return err
}
```
Note that though this example uses SHA256, Vault also supports the use of
SHA1, SHA384, or SHA512. The hash function that was used at this step will
need to be provided as a parameter when importing the key.
Finally, concatenate the wrapped keys into a single byte string.
The leftmost 4096 bits of the string should be the wrapped AES key, and
the remaining bits should be the wrapped target key. Then the resulting
bytes should be base64-encoded.
```
combinedCiphertext := append(wrappedAESKey, wrappedTargetKey...)
base64Ciphertext := base64.StdEncoding.EncodeToString(combinedCiphertext)
```
This is the ciphertext that should be provided to Vault when importing a
key into the transit secrets engine.
```shell-session
$ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE
```
### AWS CloudHSM Example
This example demonstrates how to import a key into the transit secrets engine from
an AWS CloudHSM cluster. The process and mechanisms used will apply to importing
a key from an HSM in general, but the details will differ between HSMs.
For information on creating and communicating with an AWS CloudHSM cluster, see
the [Getting Started guide in the AWS CloudHSM documentation](https://docs.aws.amazon.com/cloudhsm/latest/userguide/getting-started.html).
Communication with the HSM uses AWS's `key_mgmt_util` tool. For help setting that
up, see the [Getting Started page for key_mgmt_util](https://docs.aws.amazon.com/cloudhsm/latest/userguide/key_mgmt_util-getting-started.html).
The first step is writing the transit wrapping key to the HSM. This involves
creating a new RSA public key object with the key returned by transit's
`wrapping_key` endpoint.
```shell-session
$ importPubKey -f wrapping_key.pem -l "vault-transit-wrapping-key"
```
This will create the public key in the HSM with all of the necessary permissions.
If you're using a different tool, make sure that the usage for the wrapping key
includes the attribute `CKA_WRAP`.
The next step is wrapping the target key using the wrapping key. If the
ID of the target key is `1` and the wrapping key is `2`, the command looks like this:
```shell-session
$ wrapKey -noheader -k 1 -w 2 -t 3 -m 7 -out ciphertext.key
```
The `-m 7` flag specifies the mechanism to use for the key wrapping. For AWS CloudHSM,
7 corresponds to the PKCS11 mechanism `CKM_AES_RSA_KEY_WRAP` ([see the AWS documentation for details](https://docs.aws.amazon.com/cloudhsm/latest/userguide/key_mgmt_util-wrapKey.html)).
The `-t 3` flag specifies `SHA256` as the hash function. The result is written to a
file called `ciphertext.key`. The `noheader` flag ensures that the ciphertext does
not include an AWS-specific header.
The output from this is a binary file, which needs to be base64-encoded when it
is provided to Vault.
```shell-session
$ export CIPHERTEXT=$(base64 ciphertext.key)
$ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE
```
Once the key has been imported, it can be used like any other transit key.