Disabled customer-managed KMS keys still cost you $1/month each plus pending deletion overhead. If a disabled key has no real future use, schedule it for deletion to stop the charge, after confirming nothing still references it.
Customer-managed KMS keys are easy to create and even easier to forget. A common pattern goes like this: someone disables a key thinking they have turned it off, the encrypted data it protected gets migrated or deleted, and the key sits there quietly disabled for months. AWS keeps billing you the whole time. This check flags those keys so you can clean them up instead of leaking a few dollars a month, every month, across dozens of orphaned keys.
What this check detects
The account_unusedkms check looks for customer-managed KMS keys (CMKs) whose key state is Disabled. A disabled key cannot be used for any cryptographic operation, encrypt, decrypt, sign, or verify, yet AWS continues to charge the standard monthly fee for it as long as it exists.
The check specifically targets customer-managed keys. AWS-managed keys (the ones with aliases like aws/s3 or aws/ebs) are free and managed for you, so they are out of scope. Only keys you created and pay for show up here.
Note: A KMS key can be in one of several states: Enabled, Disabled, PendingDeletion, PendingImport, or Unavailable. A disabled key is billable. A key in PendingDeletion is also billable until the deletion window closes, but at least it is on a path to being removed.
Why it matters
The headline issue is cost, but the deeper problem is operational hygiene.
Cost that compounds quietly
Each customer-managed key costs roughly $1 per month. That sounds trivial until you multiply it across a large organization. Teams that create a key per environment, per service, or per pipeline run can accumulate hundreds of keys. If even 50 of them are disabled and forgotten, that is $600 a year for encryption keys that protect nothing. Multiply across accounts in an AWS Organization and the number gets harder to ignore.
A disabled key is a sign of unfinished work
A disabled key usually means a decommissioning job was started but never finished. Either the key is still needed (in which case disabling it was a mistake that will cause an outage when someone tries to decrypt data), or it is genuinely dead (in which case it should be deleted, not left in limbo). Both situations are worth resolving.
Warning: Before you assume a disabled key is safe to remove, check whether anything still references it. EBS snapshots, S3 objects, RDS instances, Secrets Manager secrets, and DynamoDB tables can all be encrypted with a CMK. If the key is deleted and those resources still depend on it, that data becomes permanently unrecoverable.
Audit and compliance noise
Stale keys clutter your KMS inventory and make audits harder. When a security reviewer asks "what is this key for and who can use it?", every orphaned key is a question someone has to answer. Fewer keys means a cleaner, more defensible key policy footprint.
How to fix it
The fix is to confirm the key is truly unused and then schedule it for deletion. Do not rush. KMS deletion is irreversible once the waiting period ends.
Step 1: List your disabled customer-managed keys
KMS does not give you key state directly from list-keys, so describe each key and filter:
for key in $(aws kms list-keys --query 'Keys[].KeyId' --output text); do
state=$(aws kms describe-key --key-id "$key" \
--query 'KeyMetadata.[KeyState,KeyManager]' --output text)
echo "$key $state"
done | grep -i "Disabled" | grep -i "CUSTOMER"
Step 2: Find out what the key was used for
Check the key's aliases and any grants, then look at CloudTrail to see when it was last used for a real operation.
# Aliases tell you the intended purpose
aws kms list-aliases --key-id <key-id>
# Grants reveal which services or roles can use it
aws kms list-grants --key-id <key-id>
Then query CloudTrail for recent usage:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=<key-arn> \
--max-results 20 \
--query 'Events[].[EventTime,EventName,Username]' \
--output table
Tip: If you have AWS Config enabled, the AWS::KMS::Key resource type lets you query relationships and configuration history without scripting. Config can also show you which resources reference the key through its relationship data.
Step 3: Schedule deletion
Once you are confident the key protects no live data, schedule it for deletion. KMS enforces a waiting period of 7 to 30 days, with 30 as the default. Use a long window so you have time to abort if a forgotten dependency surfaces.
Danger: Scheduling key deletion is irreversible after the waiting period ends. Any data encrypted with this key becomes permanently undecryptable. Always use the maximum 30-day window for production keys and monitor for decrypt errors during that window.
aws kms schedule-key-deletion \
--key-id <key-id> \
--pending-window-in-days 30
The key state changes to PendingDeletion. If you discover the key is still needed during the window, cancel and re-enable it:
aws kms cancel-key-deletion --key-id <key-id>
aws kms enable-key --key-id <key-id>
Alternative: keep it but stop wondering about it
If you cannot prove the key is unused but want to limit risk, leave it disabled and tag it clearly so the next reviewer knows its status:
aws kms tag-resource --key-id <key-id> \
--tags TagKey=status,TagValue=pending-review \
TagKey=disabled-date,TagValue=2024-01-15 \
TagKey=owner,TagValue=platform-team
How to prevent it from happening again
The goal is to stop disabled keys from accumulating silently. That means tagging at creation, scanning continuously, and acting on the results.
Require ownership tags on every key
Use a service control policy or a permission boundary to require that any new key carries an owner and purpose tag. This makes orphan keys traceable later.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyKmsCreateWithoutTags",
"Effect": "Deny",
"Action": "kms:CreateKey",
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/owner": "true"
}
}
}
]
}
Manage keys as code
When keys are defined in Terraform or CloudFormation, deleting the resource definition schedules the key for deletion through your normal review process. No more manual disabling and forgetting.
resource "aws_kms_key" "app_data" {
description = "Encryption for app-data S3 bucket"
deletion_window_in_days = 30
enable_key_rotation = true
tags = {
owner = "platform-team"
purpose = "app-data-encryption"
}
}
Schedule a recurring scan
Run a periodic job that flags disabled customer-managed keys and posts them to a channel for review. Here is the core logic you can drop into a Lambda on an EventBridge schedule:
aws kms list-keys --query 'Keys[].KeyId' --output text | tr '\t' '\n' | \
while read key; do
meta=$(aws kms describe-key --key-id "$key" \
--query 'KeyMetadata.{State:KeyState,Mgr:KeyManager}' --output json)
echo "$meta" | grep -q '"Disabled"' && \
echo "$meta" | grep -q '"CUSTOMER"' && \
echo "Disabled CMK found: $key"
done
Tip: Lensix runs this check continuously across all your AWS accounts and surfaces disabled, unused keys with their estimated monthly cost, so you do not have to maintain scan scripts yourself.
Best practices
- Prefer fewer, well-scoped keys. A key per major data domain is easier to manage than a key per resource. Over-provisioning keys is the root cause of orphan sprawl.
- Enable automatic key rotation on keys you keep. It costs nothing extra and improves your compliance posture.
- Always use a 30-day deletion window for production keys. The window is your safety net against a forgotten dependency.
- Tag keys with owner, purpose, and lifecycle status at creation time. Future-you will be grateful.
- Decommission keys as part of resource teardown, not as a separate afterthought. When you delete the data, plan the key's fate in the same change.
- Review your KMS inventory quarterly. Keys accumulate. A regular sweep keeps the count, and the cost, under control.
A disabled key is a small bill, but it is also a loose end. Closing it out keeps your encryption footprint tight, your audits clean, and your monthly statement free of charges for keys that guard nothing.

