The Two Common AWS KMS Anti-Patterns

Going beyond the checkbox

Josh Armitage
3 min readSep 22, 2023

When looking at security in AWS, there are two services that are the biggest determiner of your security posture. IAM and KMS. While things like AWS IAM Access Analyser are helping push the industry forward on their use of IAM, the same, unfortunately, cannot be said of KMS.

KMS is so powerful because it provides a way of enforcing bi-directional trust. I need both the permissions in IAM to use the key, and I also need the key resource policy to agree.

While no one sets out to build insecure systems, delivery teams are given incentives to deliver fast within guardrails. Better KMS key usage is functionally invisible from end users, and unfortunately no one often cares until there is a security breach.

This is not the sharp, short feedback loop that naturally leads to continuous improvement. When you look at common guardrails, you can see that they do not provide a systematic way towards effective KMS usage.

Where Compliance Falls Short

The tools we commonly use to understand compliance look at encryption as binary. Taking the AWS CIS Benchmark as an example, it’s encryption related controls are:

2.1.1 Ensure all S3 buckets employ encryption-at-rest

2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required

2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions

2.3.1 Ensure that encryption is enabled for RDS Instances

2.4.1 Ensure that encryption is enabled for EFS file systems

3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs

These are worthwhile goals as a starting point, they do not evaluate the quality of the KMS key usage, and how security principles are implemented. In a cloud-native world, keys do more than just encrypt data, they provide additional access controls at runtime.

To achieve the principle of least privilege in AWS, you need customer managed keys that enforce minimal privileges, which, as outlined at the beginning, is done through resource policies.

How KMS Improves Runtime Data Security

While a select few services, like S3, provide their own resource policies, enabling another way to achieve the bi-directional trust mechanism. Services such as DynamoDB do not.

In these cases, the KMS key can provide the same functionality. Now, rather than just needing the IAM privileges such as dynamodb:getitem I also need access to the key used to encrypt the table.

In reality, much of this opportunity is lost as KMS resource policies often contain one of two anti-patterns which undermine their use as runtime protection.

How Not To Do Resource Policies

A KMS resource policy is an IAM policy which defines who can perform what operations on or with that specific key.

An unfortunately common policy looks like the following:

{
"Version": "2012-10-17",
"Id": "bad-policy",
"Statement": [
{
"Sid": "Allow key access",
"Effect": "Allow",
"Principal": {
"AWS": ["arn:aws:iam::111122223333:root"]
},
"Action": [
"kms:*"
],
"Resource": "*"
}
]
}

This allows all principals within the account, to perform all actions with the key. Both administration and use. At this point, you might as well not have the key at all.

The following policy is an improvement, but still contains a common anti-pattern.

{
"Version": "2012-10-17",
"Id": "less-bad-policy",
"Statement": [
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": ["arn:aws:iam::111122223333:role/KMSAdminRole"]
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": ["arn:aws:iam::111122223333:root"]
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
]
}

This policy splits key administration duties, and usage of the key. The administration is locked down to a specific role. But the usage of the key is still available to the entire account.

When our compliance tooling only looks at encryption as binary, there is no feedback loop to force iteration on the resource policies themselves.

Finding the Anti-Patterns

As a proof of concept, I have written a small tool in go that will analyse the keys in an account, identifying those where these anti-patterns can be found.

You can find it here: https://github.com/JoshArmi/aws-kms-policy-scanner

--

--