CloudBurn Logo
CloudBurnHome
  • Blog
  • Docs
  • Tools
  • Features
  • Roadmap
  • Changelog
Join the CloudBurn Discord community
1.8k
Join the CloudBurn Discord community1.8k
  • Home
  • Blog
  • Docs
  • Tools
  • Features
  • Roadmap
  • Changelog
Navigation
    • Overview
    • Understanding Rules
      • CloudFront
      • CloudTrail
      • CloudWatch
      • AWS Config
      • Cost Explorer
      • Cost Guardrails
      • Cost Optimization Hub
      • DynamoDB
      • EBS
      • EC2
      • ECR
      • ECS
      • EKS
      • ElastiCache
      • ELB
      • EMR
      • KMS
      • Lambda
      • RDS
      • Redshift
      • Route 53
      • S3
      • SageMaker
      • Secrets Manager
      • Tagging
    • Overview
    • Understanding Rules
      • CloudFront
      • CloudTrail
      • CloudWatch
      • AWS Config
      • Cost Explorer
      • Cost Guardrails
      • Cost Optimization Hub
      • DynamoDB
      • EBS
      • EC2
      • ECR
      • ECS
      • EKS
      • ElastiCache
      • ELB
      • EMR
      • KMS
      • Lambda
      • RDS
      • Redshift
      • Route 53
      • S3
      • SageMaker
      • Secrets Manager
      • Tagging
Loading documentation page
CloudBurn Logo
CloudBurn

AWS cost intelligence platform that automatically identifies waste, optimizes resources, and provides actionable recommendations to reduce cloud spend.

Product

  • Features
  • Roadmap
  • Changelog
  • About
  • Blog
  • Newsletter
  • Docs
  • Contact

Free Tools

  • Lambda Cost Calculator
  • EC2 Pricing Calculator
  • S3 Pricing Calculator
  • EBS Pricing Calculator
  • Fargate Pricing Calculator
  • RDS Pricing Calculator
  • Aurora Cost Calculator
  • All AWS pricing calculators →

Newsletter

Subscribe for CloudBurn product updates, changelogs, and actionable AWS cost optimization tips delivered to your inbox.

Newsletter signup form loading.
Enter your email…
Subscribe
---- subscribers
OR SIGN UP WITH
GGH

By signing up you agree to our privacy policy.

CloudBurn © 2026 | Terms & Privacy

Built with ❤️ by Towards the Cloud

CloudBurn Rules

KMS Rules

CloudBurn cost optimization rules for AWS KMS.

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 IDScan TypeSeverityName
CLDBRN-AWS-KMS-1DiscoveryMediumKMS Customer-Managed Key Churn
CLDBRN-AWS-KMS-2DiscoveryMediumKMS 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:

  • enabledCustomerManagedKeyCount is 50 or more
  • keysCreatedInWindow is 10 or more, counting only keys created during the previous full calendar month (UTC)

How to remediate

  1. 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.
  2. 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.
  3. 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.
  4. 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
  1. 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

  1. Confirm nothing depends on the key. GetKeyLastUsage records 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.
  2. 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
  1. 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
← EMRLambda →