AWS KMS Envelope Encryption

Today the Cloudreach blog covers a topic that is hot, hot, hot given the continuing security breaches, challenges and discussions around the globe. Specifically, we’re going to talk about encryption in AWS and how to make AWS Key Management Service (KMS) secure for your needs. The functionality that KMS provides is great, and with a little bit of work you can utilise a concept called Envelope Encryption to ensure the security of your sensitive data in the AWS Cloud.  


What is it and why do you want it?

There are many different ways to secure sensitive data. In a public cloud environment such as AWS, the Shared Responsibility Model means that you have a lot of options - access control, encryption you run and manage yourself, encryption handled via services such as KMS which handle it all for you, or indeed a mix of the above.

So let’s imagine that you have one or more bits of data that you know you want to be encrypted. You might even have regulatory or compliance requirements such as HIPAA or PCI DSS that require data to be encrypted, and for there to be no method for the cloud provider to decrypt the data.  A service such as AWS Key Management Service alone then isn’t enough to do it since the single key nature of the system means that anyone with access to your Customer Master Key can decrypt it. While this risk can be reduced with IAM and key policies, to truly eliminate it we need to further secure the encryption key.

Envelope Encryption solves this problem for us. It is a method of encrypting data that requires 2 keys in order to decrypt the data back to plain text again. These keys are held in two separate places so that if a malicious person gets hold of one of them, that key by itself is useless. Only with permissions to access and use both keys, can you decrypt the data back to its original form.  


Simple Encryption Example with KMS

So we have our secret data that we need to use regularly but also need to keep it securely so that only authorised users can use it. The first step in this process would be to encrypt it. That is very easy to do - we simply ask KMS to encrypt our bit of data, and supply an ID of a KMS key to use. Here’s a CLI example:

aws kms encrypt --key-id 1234abcd-12ab-34cd-56ef-1234567890ab 
--plaintext fileb://Plaintext-data.txt --output text --query CiphertextBlob | base64 
--decode > Encrypted-data.txt

This single line command handles it for us, retrieves our key from the KMS service (as long as we have correct IAM permissions, key permissions and credentials set up to do so!) and gives us a nice encrypted file that we can store safely. Access control to the key and who can use it can be tuned down nicely with key permissions for extra reassurance, and all API interactions here would also be logged to Cloudtrail if you have it on, so as to ensure an audit trail.

Now, to get the plaintext back, we simply do a similar decrypt command:

aws kms decrypt --ciphertext-blob fileb://Encrypted-data.txt --output text 
--query Plaintext | base64 --decode > Plaintext-data-decrypted.txt

And now our Plaintext-data-decrypted will contain the original data.

As we’ve mentioned earlier, this basic encryption of data using KMS is not always good enough, so a method that further encrypts our encryption key is required - and this is where Envelope Encryption comes in.

The way this works is as follows - one key is encrypted by another key, and these two keys are never held in the same place. They need to be used in the right order, to get our data out.

Here’s a few diagrams to make this clearer.

First up, encryption both with Basic KMS and using Envelope Encryption.

Here you can see that KMS and our Plain text are combined with a key, to give our output - an encrypted key and some encrypted text. Full details of how this works are further below!

To decrypt our data, this process works in reverse as follows:

Here you can see a 2 stage process , first the encrypted key is turned into a normal key via KMS, and then the normal key is used to unlock the data back to plain text.


Practical Envelope Encryption Examples

Requirements (CLI, IAM perms etc)

You’ll need the following in place* to do this:

  • A KMS key with permissions to use it (see this page on the AWS docs for details)
  • Credentials set up for access to the account
  • AWS CLI tools installed
  • Encryption software such as openssl or PGP installed
  • Linux/OSX terminal to run the commands below, though some will translate to a Windows environment as well.

* If you are starting from scratch, we’d recommend using Cloudformation to build your AWS Infrastructure, and Sceptre as the ideal tool for managing Cloudformation. Example with AWS CLI Let’s say we have a plaintext-data.txt file full of things we need to encrypt.  


Encrypting it.

1. Let’s make sure our plain text is there to start with

$cat plaintext-data.txt

2. First we use KMS to get an encrypted cipher text key and save this to a file. As this is encrypted with our KMS key, saving it to a file is ok as it needs KMS key access to decrypt again. Insert your own AccountID (ACCID) and Key Id (KEYUID)

$aws kms generate-data-key --key-id 
arn:aws:kms:eu-west-1:ACCID:key/KEYUID  --key-spec AES_256 --output 
text --query CiphertextBlob | base64 --decode > EncryptedEnvelopeKey

That ‘base64 -- decode’ part might look a little odd to you - it had me stumped for a while. Turns out that the ciphertext that is returned by a successful encrypt command is base64-encoded text, therefore,we must decode it before we can make use of it.

3. Now, we need the plaintext version of our ciphertext key, so we decrypt this to plaintext and we have it ready for use for our second encryption tool to use.

PlaintextEnvelopeKey=$(aws kms decrypt --ciphertext-blob 
fileb://EncryptedEnvelopeKey --output text --query Plaintext)

4. Encrypt our original secrets file with a tool of your choice -  in this case OpenSSL. Caution: after using the plaintext key, unset to clear it from memory as per below.

$openssl enc -in plaintext-data.txt -out encrypted-data.txt -e 
-aes256 -k $PlaintextEnvelopeKey
$unset PlaintextEnvelopeKey

5. Save our encrypted key somewhere This stage is up to you - as long as it is somewhere you will not lose it and can easily get it when you need it! See the section below on Storing your keys safely.  



1. Get our saved encrypted key Wherever you kept the above key, now is the time to get it back! I’m going to assume it’s back in EncryptedEnvelopeKey in the current directory.

2. Using KMS, decrypt to a plaintext key. Note that this contains metadata such as the KMS key id, so you need all the access you had before to decrypt!

PlaintextEnvelopeKey=$(aws kms decrypt --ciphertext-blob fileb://
EncryptedEnvelopeKey --output text --query Plaintext)

3. Now we have plaintext, use with our Openssl to decrypt the original document. Remember to unset the plaintext key variable as soon as we don’t need it.

openssl enc -in encrypted-data.txt -out plaintext-data.txt -d -aes256 -k 
unset plainkey

4. Now make sure our data is intact

#cat plaintext-data.txt


Storing your keys safely

A quick word on storing keys - although the encrypted key we produce above is encrypted, you should still follow good security practices around storage, audit and security.

For example, an AWS S3 bucket could work, but you would need to be sure to use strong bucket and IAM policies to make sure access is limited to those who need it.

It would also be a very good idea to log access to this bucket (AWS bucket logging), and perhaps even use AWS Lambda and SNS to alert your security team when access occurs, so they can make sure it’s authorised.  

Additionally, KMS access should be controlled - you can limit who can administer and use your KMS keys, using key policies, and using Cloudtrail the 'Decrypt', 'Encrypt' and 'Createkey' actions are logged to AWS Cloudtrail.  


Final Words

You should by now understand Envelope Encryption and how to implement it using AWS KMS. With this newfound knowledge, there’s no excuse for not encrypting data in the Cloud. Security breaches do happen commonly, and securing your data with good methods like this could be the decisive factor that saves your bacon if the worst occurs.  


Further Reading Links

  • aws-kms-envelope-encryption