These rules review customer-managed KMS key inventories for the two ways key spend grows without anyone deciding it should: Regions accumulating keys faster than anyone retires them, and individual keys that nothing has used in months.
| Rule ID | Scan Type | Severity | Name |
|---|---|---|---|
| CLDBRN-AWS-KMS-1 | Discovery | Medium | KMS Customer-Managed Key Churn |
| CLDBRN-AWS-KMS-2 | Discovery | Medium | KMS Key Without Recent Recorded Usage |
Both rules read the same regional evidence, collected once per Region. CloudBurn enumerates KMS keys through Resource Explorer, then calls DescribeKey to keep only keys that are customer-managed, Enabled, and not already scheduled for deletion. For each of those keys it calls GetKeyLastUsage for usage evidence and ListKeyRotations to price rotated key material. ListAliases is read for cohort detection, but raw alias values are normalized and hashed before aggregation, so no alias string is retained in the findings.
CLDBRN-AWS-KMS-1
KMS Customer-Managed Key Churn
Scan type: Discovery
Severity: Medium
What it checks
Flags a Region whose customer-managed key inventory is large, or growing quickly, enough to be worth a lifecycle review. The finding is scoped to the Region rather than to one key: its resource ID is kms-key-churn/<region>.
Alongside the counts that trigger the finding, the review carries the evidence you need to act on it: the estimated monthly key storage cost, how many keys are multi-Region, how many have been rotated, a usage-evidence breakdown across the Region's keys, and alias pattern groups that show which keys were created from the same naming template. Those groups are how automated key creation shows up: a pattern with 40 keys behind it usually means a pipeline mints a key per branch, per preview environment, or per tenant and never cleans up.
Why it matters
Each customer-managed key costs $1 per month, and each rotation of a key keeps the previous key material billable at another $1 per month, capped at $3 per key per month. One key is not worth a meeting. Four hundred keys created by a pipeline nobody remembers configuring is $400 to $1,200 a month for cryptographic material that mostly protects nothing. Key sprawl also compounds: keys are rarely deleted, because deletion is irreversible and nobody wants to be the person who broke a restore, so the inventory only grows until somebody reviews it deliberately.
What triggers a finding
Either of these conditions, evaluated per Region:
enabledCustomerManagedKeyCountis 50 or morekeysCreatedInWindowis 10 or more, counting only keys created during the previous full calendar month (UTC)
How to remediate
- Start with the alias pattern groups in the finding. A group with many keys behind it points at the automation that creates them, which is where the fix belongs.
- Check the usage-evidence counts. Keys reported as having no recorded KMS usage since creation are the safest candidates and are flagged individually by CLDBRN-AWS-KMS-2.
- Where the same key can serve several resources, consolidate. A key per environment or per data classification is usually enough; a key per resource rarely earns its cost.
- Prevent rotation cost where rotation is not required. Automatic rotation is free to configure, but the first two retained key versions each bill another $1 per month; the charge is capped at that point, so disabling rotation on a key that has already rotated twice saves nothing and existing key material keeps billing. Disable it before the first paid rotation on keys where your compliance baseline does not call for it:
aws kms disable-key-rotation --key-id 1234abcd-12ab-34cd-56ef-1234567890ab
- Retire keys you no longer need. Disable first, watch for breakage, then schedule deletion with the longest window you can tolerate:
aws kms schedule-key-deletion \
--key-id 1234abcd-12ab-34cd-56ef-1234567890ab \
--pending-window-in-days 30
CLDBRN-AWS-KMS-2
KMS Key Without Recent Recorded Usage
Scan type: Discovery
Severity: Medium
What it checks
Flags individual enabled customer-managed keys that are at least 90 days old and have no recorded KMS cryptographic use across a tracking window that is itself at least 90 days long. The rule reads GetKeyLastUsage, so it reflects what KMS itself recorded, not a CloudTrail query you have to run yourself.
Usage evidence comes back in one of four states. used means KMS recorded a cryptographic operation and reports when. no_kms_usage_since_creation means the key was created after tracking began and has never been used. unobserved_before_tracking means the key predates the tracking window, so its whole history is not visible, but nothing has used it since tracking started. unavailable means KMS returned no tracking start date, or the call was denied.
Why it matters
An unused customer-managed key costs $1 per month, or up to $3 if it has been rotated, and keeps billing for as long as it exists. Keys outlive what they protected: the bucket is emptied, the database is deleted, the service is decommissioned, and the key stays enabled because deleting a key feels riskier than paying a dollar. That reasoning is correct for one key and expensive across hundreds. A key with no recorded use in a complete 90-day window is the clearest evidence you will get that nothing depends on it.
What triggers a finding
All of the following must be true:
- Usage evidence is not
unavailable - The key was created 90 or more days ago
- A tracking start date exists and is 90 or more days in the past, so the no-usage window is complete
- Either the key has no recorded last-usage timestamp and its evidence is not
used, or its last recorded usage is 90 or more days in the past
A key whose evidence is unobserved_before_tracking is still evaluated. KMS only shows usage from the tracking start date onward, so a key older than that window can be flagged on the strength of the complete window that is visible.
When DescribeKey or GetKeyLastUsage metadata is incomplete for any key in a Region, the whole per-key dataset for that Region is marked unavailable and the rule is skipped there rather than run on partial evidence. The scan carries a diagnostic naming how many keys lacked each kind of metadata, so the gap is visible instead of reading as a clean result.
How to remediate
- Confirm nothing depends on the key.
GetKeyLastUsagerecords KMS cryptographic operations, so a key used only as a grant target or referenced by a resource that has not been read recently can still look unused. Check the key policy, grants, and any resources configured with the key ARN before acting. - Disable the key and wait. Disabling is reversible and surfaces anything that still needs it:
aws kms disable-key --key-id 1234abcd-12ab-34cd-56ef-1234567890ab
- If nothing breaks over a full business cycle, schedule deletion. The pending window is the last point at which you can cancel, so prefer a long one:
aws kms schedule-key-deletion \
--key-id 1234abcd-12ab-34cd-56ef-1234567890ab \
--pending-window-in-days 30
Deleting a KMS key permanently destroys the key material. Anything encrypted under it becomes unrecoverable, including snapshots and backups you may not have inventoried. Disabling first, and keeping the key disabled for longer than your longest backup retention period, is the part of this that matters.
See Also
- CLI discover command -- scan live KMS keys
- Understanding Rules -- rule anatomy, findings, and enabling or disabling rules
- SDK Reference -- run discovery programmatically