A KMS key costs a dollar a month, which is why nobody reviews it, and why accounts accumulate hundreds. The charge that grows is the other one: every encrypt and decrypt is an API request, and services like S3 make one per object operation unless you turn on the setting that stops them.
What does AWS KMS charge for?
Keys and requests. From the AWS KMS pricing page, "Each AWS KMS key that you create in AWS KMS costs $1/month (prorated hourly)", and requests are charged per 10,000. The per-request rate is region-specific and the pricing page renders it dynamically, so take it from there rather than from here; AWS's own worked examples for a standard symmetric key use $0.03 per 10,000 requests, and $0.15 per 10,000 for RSA 2048 asymmetric requests.
What counts as a request is worth checking against the
KMS concepts documentation,
because every GenerateDataKey and Decrypt call from a
service acting on your behalf is billable.
There is a free tier, and it is a request allowance rather than a key allowance: "AWS KMS provides a free tier of 20,000 requests/month calculated across all Regions that the service is available." Keys are never free. Two exclusions apply: "Plaintext API operations and requests to API operations such as Sign, Verify, Encrypt, Decrypt, and GetPublicKey that reference asymmetric KMS keys are excluded from the free tier."
Why does key rotation cost extra?
Because rotation keeps the old key material, and AWS charges for it. This is the detail most people miss: "For KMS keys that you rotate automatically or on demand, the first and second rotation of the key adds $1/month (prorated hourly) in cost."
So a key you rotate is not $1 a month. After two rotations it is $3 a month, and that is the ceiling on the rotation component. On its own that is trivial. Across an organisation with automatic rotation enabled on 400 keys it is $1,200 a month rather than $400, arriving gradually as rotations happen, with no event to attribute it to.
| Key state | Monthly key charge |
|---|---|
| Created, never rotated | $1 |
| After first rotation | $2 |
| After second and subsequent rotations | $3 |
How rotation works, and why the old material is retained, is set out in rotating AWS KMS keys.
Rotation is still the right default for most keys. The point is that it is a priced decision rather than a free one, and enabling it fleet-wide triples a line item nobody was watching.
What makes the request charge grow?
Services calling KMS on your behalf, once per object. AWS's own S3 example is the clearest statement of the shape: "1 KMS key used to encrypt 10,000 unique files that are collectively decrypted for access 2,000,000 times per month."
One key, ten thousand objects, two million requests. At the $0.03 per 10,000 used in AWS's example that is $6 a month for a single dollar's worth of key. Scale the object count and the access pattern and the request meter passes the key meter by orders of magnitude. A data lake read by Athena queries that fan out across thousands of objects is exactly this pattern.
Which is why the largest KMS bills belong to accounts that think they are barely using KMS. They created one key, enabled SSE-KMS on a bucket, and the request volume tracks how often anything reads the data.
How do you cut S3 KMS requests by 99%?
S3 Bucket Keys. Per the S3 Bucket Keys documentation, the feature "can reduce AWS KMS request costs by up to 99 percent by decreasing the request traffic from Amazon S3 to AWS KMS." It works by having S3 generate "a short-lived bucket-level key from AWS KMS", which then "will create data keys for new objects during its lifecycle", so S3 stops calling KMS once per object.
Treat 99 percent as a ceiling rather than an expectation, because AWS qualifies it: "Unique bucket-level keys are fetched at least once per requester", and "AWS KMS request savings reflect the number of requesters, request patterns, and relative age of the objects requested. For example, a fewer number of requesters, requesting multiple objects in a limited time window, and encrypted with the same bucket-level key, results in greater savings." A bucket read by many distinct roles saves less than one read by a few, because each requester fetches its own bucket-level key so the access shows up in CloudTrail.
It is a bucket setting, it is off on older buckets, and enabling it changes no application code:
aws s3api put-bucket-encryption --bucket my-bucket \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/abcd-1234"
},
"BucketKeyEnabled": true
}]
}'
Check which of your encrypted buckets are missing it:
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
cfg=$(aws s3api get-bucket-encryption --bucket "$b" 2>/dev/null \
--query 'ServerSideEncryptionConfiguration.Rules[0].[ApplyServerSideEncryptionByDefault.SSEAlgorithm,BucketKeyEnabled]' \
--output text)
case "$cfg" in aws:kms*) echo "$b $cfg" ;; esac
done
Any row showing aws:kms with None or
False is paying per-object KMS requests it does not need to. Note
that enabling it applies to newly written objects; existing objects keep their
original encryption context until rewritten.
Are unused keys worth deleting?
Usually not worth the risk, and that is the honest answer rather than the cost-optimal one. A KMS key is $1 to $3 a month; data encrypted under a key you delete is unrecoverable, permanently. The asymmetry is extreme enough that hunting keys for savings is a bad trade unless you can prove nothing references them.
The safer lever is not creating them. A key per environment or per data classification is defensible. A key per bucket, per table or per microservice multiplies a fixed monthly charge for no additional isolation in most threat models, since a grant or a scoped key policy separates access without a second key, and it is the pattern that turns $1 into four figures.
If you do want to identify candidates, look for keys with no recent
Decrypt or GenerateDataKey activity in
CloudTrail, and note that KMS API calls are
management events, so they are in the free first copy rather than the expensive
second one. A key with no cryptographic use for a full retention period is a
candidate for the
pending-deletion window,
which is the reversible step. Deletion is not. Where the goal is isolation rather
than savings, the
key policy
usually does the job that a second key was created for.
Is your KMS bill keys or requests?
Usage type separates key-months from requests, which is the only breakdown that tells you which lever applies:
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-08-01 \
--granularity MONTHLY \
--metrics UnblendedCost UsageQuantity \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["AWS Key Management Service"]}}'
Key-dominated means too many keys, and the fix is a naming and provisioning policy rather than deletion. Request-dominated means an access pattern, and Bucket Keys is the first thing to check. Both are invisible in Cost Optimization Hub, which covers neither KMS nor S3.