KMS — What is it? how to use it? Where does it come from? Should I feed it?
First of all, what is KMS?
It stands for Key Management Service, is a managed service that can be used to encrypt your data. It is a highly available solution for storage, management and auditing cryptographic key’s usage through your application's data and data stored on AWS services.
Confusing right? Let me put it another way, KMS can be used to secure data in YOUR application and IS used to encrypt data that is saved across and by AWS.
Before start talking about KMS, we need to start talking about cryptography.
I’ll try to keep it simple[a.k.a Non-Math stuff coming].
Cryptography is a specific area of Cryptology, which is the science of hidden values/texts. Cryptology is composed of Cryptography and Cryptanalysis. Cryptanalysis deals with analysing cryptographed material and Cryptography deals with written information in a hidden way.
The basic components of cryptography are: A key, the Message and the cryptographed material or Cipher. Once you apply a Key to a Message using a cryptographic algorithm, the result is a cipher.
Once you have a cipher, it is only possible to reverse from cipher, to the plain-text if you have the key. The strength of ANY cryptographic environment is to keep the key safe, guaranteeing that only who has the right permission will have access to.
In terms of Keys, there are two approaches that can be used, the first one is a Symmetric Key, the second one is an Asymmetric key. In a Symmetric system the SAME key is used both to encrypt and decrypt.
In Asymmetric system, there are two keys, Public Key (PubKey) and a Private Key (PvtKey), if you encrypt a message with the PubKey it can ONLY be decrypted using the PvtKey and if you encrypt a message with a PvtKey it can ONLY be decrypted using the PubKey. In summary only the second part can decrypt what was encrypted by the first part.
The PvtKey, as its name suggests MUST BE kept in secret and the PubKey is MEANT TO BE public.
Now, if you think it through, this has an enormous potential.
If you Encrypt a message with YOUR PvtKey and send the Cypher to a friend, this Cypher will ONLY be decrypted using your PubKey hence, the receiver will be sure that the message was sent by you. Authentication.
If you Encrypt a message with yours FRIEND's[Receiver] PubKey and send the Cypher, the receiver will ONLY be able to Decrypt it using his/hers PrvKey, in this case the Receiver will be sure that the message was meant to him. Privacy.
In one hand you have Authentication but DON’T have Privacy, everyone has access to a PubKey so everyone will be able to Decrypt the message. In the other hand you have Privacy but you DON’T have Authentication because everyone can use your PubKey to send over a message, but you CAN’T be sure on who sent the message.
To guarantee Privacy and Authentication, the solution is quite simple.
Well, use your PrvKey to Encrypt a message, then take this message[that now is a Cypher], and Encrypt it again using your FRIEND's[Receiver] PubKey, send the message over.
Once the message is received by the receiver, he/she will use the PvtKey to Decrypt [This way be sure that the message was Private] and Decrypt it again using the senders PubKey[This way guarantees the Authentication].
Of course it is a little more complicated than that, but that is the general idea, if you are using a Symmetric approach, you only have ONE key, the same key encrypts and decrypts, and if you have a Asymmetric approach, the keys will came in pairs (PvtKey and PubKey) and only one can Decrypt what was encrypted by the Other.
There is a good video in here that covers it in a lot more detail.
Back to KMS
Now that we understand the basics about keys, let’s dive a little deeper into KMS. The first important concept is Customer Master Keys ( CMK).
CMK is a key that is used to encrypt and decrypt up to 4KB of data, usually someone uses it to generate data keys used outside of KMS for data encryption. Master keys are 256 bits in size.
In terms of CMK there are 3 types:
Customer managed CMKs are CMKs created, owned and managed by the customer. The customer has full administrative power over the CMKS.
AWS Managed CMKs are CMKs used by an AWS service that integrates with KMS. You can view and audit AWS Managed CMKs HOWEVER you CANNOT manage nor change their permissions, also, they CANNOT be used in a cryptographic operation of your application.
AWS Owned CMKs are CMKs that[as its name suggests] does not belong to any AWS account. They are CMKs that AWS owns and manages for multiple purposes. A customer CANNOT view, nor manage, audit or use AWS Owned CMKs.
Another concept that is important to this scenario is Data Keys and Encryption Context, Data Keys are keys that you can use to encrypt large amounts of data and other keys. You can use a CMK to generate the data keys, but it is important to highlight that KMS DOES NOT store, manage or track data keys, the responsibility associated with those are of the customer, Data Keys can be generated in 128 or 256 bits length and encrypted under a Master Key that the customer defines[More about that latter]; Encryption Context are optional set of a key-value that contains contextual information about the encrypted data.
About AWS Regions and KMS
As we know [and if "we" don’t know I recommend reading this] AWS works with the concept of regions. Regions are areas in which AWS groups data centers. “Each AWS Region consists of multiple, isolated, and physically separate AZ’s within a geographic area.”. There are resources that spam across all regions and there are resources that are binded to a region.
KMS is one of those services that the resources[Keys] lives inside a region, better saying KMS is a global service that can be used in all regions, but CMKs are resources that can only be used in the region where it was first created. It means that if you want to migrate an encrypted resource from one region to another you WILL HAVE TO create a CMK in the destination region and, in this case, you will have TWO CMKs been used with ONE resource producing two separated encrypted materials.
The second option is to create an AWS Managed CMK, in this case AWS and KMS will take care of that for you, in the end you will have ONE AWS Managed CMK used with ONE resource, producing two separated encrypted materials.
Performing cryptographic operations
Now that we understand the general concepts of KMS, let’s start using it.
Creating a Key(create-key)
You can use the CreateKey to create symmetric and asymmetric CMKS, by default create-key creates symmetric keys.
Using AWS CLI, once you run :
aws kms create-key --description “this is a test”
The output will be something like:
This output presents:
KeyId: Which is the Key's Id, very intuitive.
Arn: Which which is a unique name for that resource[Key].
Some more very intuitive information, but NO KEY is returned.
Creating an alias (create-alias)
Now that we have a key created, you will use the KeyId to perform cryptographic operations programmatically, KeyId is a sequence of number and letters that identifies a CMK in your account, unless you have a unique skill to memorize all of those it is highly recommended to create an alias.
Alias are optional names that you can add to your keys to make it easier to manage your keys.
instead of memorizing this:
you can memorize key1, after running this:
sudo aws kms create-alias --alias-name alias/key1 --target-key-id ac155555–35af-aaaa-a1ea-fafa9b3f3fc8
Important: the alias must start with a “alias/” prefix.
So far we have explained[hopefully everyone is understanding what we are saying ;) ] What is KMS, cryptograph premisses, the basic structure of KMS and how to create Keys and aliases, all of that pointing now to use Keys[Through alias] to encrypt and decrypt contents. There are four commonly used AWS KMS APIs:
- GenerateDataKey and GenerateDataKeyWithoutPlaintext
To encrypt a file all you have to do is call the encrypt api passing the key-id [you can use the alias] and what you want to encrypt.
aws kms encrypt --key-id alias/key1 --plaintext fileb://fileName
the response will be something like this:
CiphertextBlob is the encrypted message, the key you used and the type of algorithm used.
When decrypting a cipher you don’t need to pass the key-id. This parameter is only required in case you use an Asymmetric key. If you have used a Symmetric key KMS can get the CMK from the Metadata on the blobfile.
The command is something like this:
aws kms decrypt --ciphertext-blob fileb://BlobFileName
When running this command you might find an InvalidCiphertextException. This is probably due to the fact that you are trying to decrypt a blob that is not in the right format or it is not on base64.
In a MacOs try this:
aws kms encrypt --key-id alias/key1 --plaintext fileb://fileName --output text --query CiphertextBlob | base64 -d > encryptedtest
sudo aws kms decrypt --ciphertext-blob fileb://BlobFileName output text --query Plaintext| base64 -d > decrypted2
GenerateDataKey and GenerateDataKeyWithoutPlainText
Now, things are gonna start to be really fun. KMS has the ability to generate DataKeys, these keys are particularly useful to encrypt your data using the DataKey instead of directly using a CMK. The DataKey is generated by AWS KMS using a CMK, and AWS keeps no record of the DataKey.
So, you use your CMK to generate a DataKey, you encrypt your data using the DataKey, and that is it.
“Wait! you said AWS does not keep record of the DataKey, so how I’m supposed to decrypt? Should I keep a record of my keys? That doesn’t make any sense!”
Yes, it doesn’t!
It is time to talk about a concept called Envelope Encryption. EC is a technique where you encrypt data using a data key then encrypt that data key under another key and you send the Encrypted Data and Encrypted Data Key all together.
Let’s build an exemple.
Step 1 — You generate DataKeyA, using CMKA, and you encrypt MessageA, resulting in CipherA.
CipherA = MessageA + DataKeyA
Step 2 — Now you encrypt DataKeyA, using CMKB, generating CipherB
CipherB = DataKeyA + CMKB
Step 3 — And now you can packet CipherA, together with CipherB, under another DataKeyN or Another CMKN …
Now, the receiver with access to CMKB will be able to decrypt DataKeyA and then decrypting CipherA getting the original message.
Really recommend the first 10–15 minutes of this video here.
Now the rest of the process is pretty simple. To generate a DataKey you can call generate-data-key calling:
sudo aws kms generate-data-key --key-id alias/key1 --key-spec AES_256
that will resulting in:
CiphertextBlob is the Plaintext[that contains the DataKey] encrypted under the CMK(KeyId) you specified.
The same happens with GenerateDataKeyWithoutPlainText:
sudo aws kms generate-data-key-without-plaintext --key-id alias/key1 --key-spec AES_256
The only difference is that there is no Plaintext being returned, you will have to call decrypt, passing the CiphertextBlob to decrypt the DataKey and then use it to encrypt the message.