AWS KMS is one of those services that works tirelessly in the background but doesn't get a lot of love. It's common to automatically encrypt every service as part of development and infrastructure-creation workflow, and this usually happens through KMS AWS-owned keys. There is nothing wrong with this, and usually, this will easily fill any encryption compliance needs you have. However, there are more less-commonly known features and configurations without KMS that are not talked about as much.
What is KMS? Put simply, KMS is the AWS key management service that allows you to encrypt your data with keys that are either managed by AWS or you. You can create both symmetric and asymmetric keys. KMS uses envelope encryption, which means it encrypts data with a root key. The data key is what is used to encrypt your data.
root key --> encrypts data key --> encrypts plaintext
The keys are decrypted within a FIPS validated HSM, and when not in use they are encrypted and stored in persistent storage isolated from the HSMs. If there were ever an attempt to remove the actual hardware hosting the key material, the power would be killed to the storage rack, wiping all key material from storage. This differs from other HSMs where material is persisted on HSMs. That is the key difference between AWS KMS and other standard providers: The HSMs in use do not persistently store key data.
Note: The KMS Key itself never leaves AWS. There is no ability to 'download' the key for usage in other places, except Data keys
Types of Keys
KMS Keys
Data Keys
Kata keys are symmetric keys similar to what is detailed above, hoewver you can download these keys for use outside of AWS. When using a data key, you are returned:
Encryption is done as normal using the plaintext key, plaintext --> encrypt plaintext data key --> encrypt ciphertext
Decryption must be done via the KMS Decrypt API call, passing the encrypted version of your data key. This decrypts your plaintext data key, which is used to decrypt the data.
Key Storage
KMS supports multiple storage options for storing your keys securely utilizing either CloudHSM or an external custom key store such as Hashicorp vault. I won't discuss these here, but know that each is an option. CloudHSM is an excellent product that is FIPS 140-2 validated. The good thing about CloudHSM is the ability to integrate it tightly with your IAM access controls, meaning you don't have to spend weeks configuring logging, permissions, policies, etc.
ABAC
Attribute-based access control (ABAC) provides a unique way to manage permissions to KMS CMKs without having to consistently edit permissions. However, it is important to consistently audit key tags to ensure principals are not inadvertently locked out of accessing a key. Give permissions to edit tags to only people who need them, ideally this is a dual-control scenario where multiple people must be involved to edit permissions.
Note: Remember that a key alias doesn't represent a KMS key in the resource section of an IAM policy. Giving a user access to use alias/MyEncryptionKey does not give that user access to the target key.
Some of the unique features around KMS are specific KMS ABAC condition keys such as the following:
The benefit of using the kms:ResourceAlias is the fact that you can use an alias in a policy without needing to list every single key ARN in the policy. Aliases are much more readable. An alias acts as a pointer to a key, so the alias target key can change and the alias remains the same. This could be considered a good or bad thing, depending on how your key management process is:
Pro: If you need to change the underlying key, simply point the alias at a new key
Con: Permissions to the underlying key are required, meaning applications may stop working if an alias is changed or removed without coordination
Note: Alias do not work with policies in the Resource block. You must use the Resource/Request alias condition key.
Utliize the aws:ResourceTag/tag-key condition key to control which users have access to which specific keys based on the tag of that key. Similarly the aws:RequestTag/tag-key can be utilized to control deletions of keys. This gives extreme flexibility to controlling who can do what with keys, and makes controlling access to highly-sensitive data much easier.
ABAC helps to avoid the problem of having to constantly edit key policies. Instead, you specify user key access based on tags. For example, you apply a permission policy to users/groups who are in charge of production development that gives them kms:Encrypt and kms:GenerateDataKey access to keys with a tag of Env=Prod
KeySpec
The Key spec is a property of a key that represents the configuration of that key. It differs depending upon the type. More can be read here. The important part of KeySpec is that it can be used as a condition key to strictly control what type of keys are created. The following policy for example allows the principal to create only RSA asymmetric KMS keys:
{
"Effect": "Allow",
"Action": "kms:CreateKey",
"Resource": "*",
"Condition": {
"StringLike": {
"kms:KeySpec": "RSA_*"
}
}
}
Something like this is incredibly useful but hardly implemented. You can force users to only perform kms:Encrypt and kms:Decrypt with key with a spec of SYMMETRIC_DEFAULT. You can also deny permission to delete, for example, your RSA keys if you require them for business-critical operations. The possibilities are endless.
AEAD
AEAD stands for authenticated encryption and associated data. More can be read about it here. But to wrap your head around it, take it at face value. Authenticated encryption -- the ciphertext is authenticated to prevent tampering with it directly. Associated data -- data that is associated with the encrypted data through an encryption context.
An EncryptionContext is the KMS version of authenticated data. Put simply, it is plaintext data that gets associated with the encrypted data to provide extra integrity protection.
For example, if you put data into a k/v database, you might encrypt that data first. You then proceed to use the unencrypted database key as the EncryptionContext. An attacker then tries to retrieve the encrypted data, however without knowing the key (in the k/v pair) is the context, they aren't able to provide any EncryptionContext. Their attempt has not authenticated properly and they are blocked from performing the kms:Decrypt operation.
There are much more intricate details with AEAD that are beyond the scope of even the public AWS docs, and there is no need to dive into the implementation unless you're curious. AWS handles it all for you.