Skip to main content
orphan · aws

Enabled customer-managed KMS keys with no aliases and no provable use

resource types
1
rule IDs covered
1
severity
low

What does ZopNight detect here?

Customer-managed KMS keys bill $1 monthly whether or not anything encrypts under them. ZopNight nominates enabled keys with an alias count of 0 as unused candidates, but only when measured request activity or billing-backed cost can actually prove the silence, because deleting a key that still protects data destroys that data.

Signal and threshold

How ZopNight evaluates Enabled customer-managed KMS keys with no aliases and no provable use.
Field Value
Rule IDsRC-058
Categoryorphan
Severitylow
Metricnone — pure configuration read
Sourcekms_unused.go

The most dangerous dollar in the directory

The saving here is $1 per key per month. The downside of getting it wrong is unbounded: a KMS key still referenced by an EBS volume, an S3 bucket, or an RDS snapshot renders that data permanently unreadable once the key is gone. That asymmetry shapes everything about this rule. It is the most heavily guarded orphan check in the AWS set, and it deliberately says “may be unused, verify” rather than “delete”.

Zero aliases is a proxy, and the rule admits it

KMS exposes per-key usage only through CloudTrail, which discovery does not join, so there is no last-used timestamp to gate on. What discovery does emit is the alias count, and an enabled customer-managed key with zero aliases (nothing human-facing points at it) is a strong candidate. Candidate, not verdict: services can reference keys by raw ARN with no alias involved.

Proof, or abstention

Before firing, the rule demands the silence be measurable, through either of two independent signals. A present per-key request metric showing zero requests per day is activity proof; billing-backed cost sitting at the bare $1 base is cost proof, since KMS adds $0.03 per 10,000 requests on top of that flat key fee and paid request charges mean the key is alive. Any measured activity, or cost above the base, suppresses. And when activity could not be measured and the cost figure is a rack-rate estimate rather than a real invoice, the rule abstains entirely. An unprovable orphan stays unflagged.

Do the verification the rule cannot

Terminal window
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=<key-id> \
--start-time "$(date -u -v-90d +%Y-%m-%dT%H:%M:%SZ)" --max-results 20

Ninety days of no Encrypt/Decrypt/GenerateDataKey events is the confirmation worth having.

Deletion is scheduled, never instant

KMS refuses immediate deletion: you schedule it with a 7–30 day waiting period, during which the key is disabled and any surviving dependency surfaces as an error you can still undo. Use the full 30 days for anything with history. Disabling the key first and waiting a billing cycle is the even gentler path: reversible, and it flushes out the annual batch job nobody remembered.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

417 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

417 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·