# KMS key-strategy decision matrix (2026)

Companion artifact for the FactualMinds post **AWS KMS Encryption Architecture**.
Pick the *coarsest* key boundary that still satisfies your isolation, audit, and contractual
requirements. Per-tenant CMKs are the most expensive and the least scalable option — choose them
only when a contract or regulator names them.

## Step 1 — key ownership tier

| Tier | When to use | Cost | Audit (CloudTrail) | Rotation control |
|------|-------------|------|--------------------|------------------|
| **AWS owned key** | Encryption-by-default where you do not need to audit or rotate the key yourself | $0 | Not visible to you | AWS-managed |
| **AWS managed key** (`aws/<service>`) | Legacy default for some services; *no new ones created since 2021* | $0 storage; you pay per request | Visible in your trail | AWS-managed, annual |
| **Customer managed key (CMK)** | You need key policy control, your own rotation, deletion, audit, or grants | $1/key/mo + $1/mo per rotation (first 2) + per-request | Full | You |

> Default to **AWS owned keys** for convenience workloads. Step up to a **CMK** only when you can
> name the control you need (policy, rotation cadence, audit, BYOK, deletion).

## Step 2 — CMK boundary (the part teams get wrong)

| Boundary | Key count at scale | Throttle exposure | Use when |
|----------|--------------------|--------------------|----------|
| **One CMK per data classification** (e.g. `pii`, `financial`, `default`) | 3–6 per account | Low — few keys, requests batched | **Default.** Tenant isolation via encryption context + grants |
| **One CMK per account/stage** | 1–N (N = accounts) | Low | Account is already the isolation boundary |
| **One CMK per tenant** | thousands | **High** — see throttle note | Contract/regulator names per-tenant keys, or true BYOK |
| **One CMK per resource** | unbounded | Very high | Almost never |

### The shared-quota note (why per-tenant CMKs do not buy you throughput)

KMS request-rate quotas are **per account + per Region + per key type**, *not per key*. In most
Regions the symmetric cryptographic-operations quota is **10,000 req/s shared** across *every*
symmetric CMK in that account+Region (HMAC keys included). Splitting one CMK into 3,000 per-tenant
CMKs does **not** give you 3,000 × 10,000 req/s — every `GenerateDataKey`/`Decrypt`/`Encrypt` call
still counts against the same shared 10,000 req/s pool. (RSA keys share 1,000 req/s; ECC/SM2 share
1,000 req/s; quotas vary by Region and are adjustable except the CloudHSM key store quota.)

## Step 3 — tenant isolation without per-tenant keys

Use **encryption context** + **grants** on a shared classification CMK:

- Encrypt every object with `EncryptionContext={"tenant": "<tenant-id>"}`.
- Scope each tenant's role with a key-policy / IAM condition on
  `kms:EncryptionContext:tenant`.
- A cross-tenant decrypt fails because the context does not match — same cryptographic isolation
  guarantee as separate keys, without the per-key bill or the key-management sprawl.

## Step 4 — custom key store only when required

| Need | Answer |
|------|--------|
| FIPS 140-2 Level 3 single-tenant HSM under your control | **CloudHSM key store** (non-adjustable request quota — size it deliberately) |
| Keys held outside AWS for sovereignty / regulator demand | **External key store (XKS)** — symmetric only, double encryption, expect worse latency/durability/availability than native KMS |
| Default | Native KMS CMK |

## Decision flow (text)

1. Do you need to audit, rotate, or control the key policy? **No → AWS owned key. Done.**
2. Yes → CMK. Can isolation be expressed as data classification? **Yes → one CMK per classification + encryption context per tenant.**
3. Does a contract/regulator name per-tenant keys or BYOK? **Yes → per-tenant CMK; budget the $1/key/mo and design around the shared request quota (data-key caching, S3 Bucket Keys).**
4. Does a regulator require keys outside AWS or a dedicated HSM? **Yes → XKS or CloudHSM key store. Else → native KMS.**
