AWS KMS β
Key Management Service
The complete guide to encryption and key management in AWS. From understanding basic cryptography to designing multi-account encrypted architectures β KMS is the foundation of data protection.
β‘ KMS in 30 Seconds
- KMS manages encryption keys β it does NOT store your data, it protects the keys that encrypt your data
- Uses envelope encryption: KMS generates a data key β you encrypt data locally β KMS encrypts the data key
- Integrates natively with 100+ AWS services (S3, EBS, RDS, Lambda, DynamoDBβ¦)
- Key policies control WHO can use and manage keys β separate from IAM policies
- Keys never leave KMS unencrypted β they are processed inside FIPS 140-2 validated hardware
What is Encryption & KMS
Every piece of data in the cloud faces threats: unauthorized access, insider threats, compliance requirements, and data breaches. Encryption is the last line of defense β even if someone gains access to your storage, encrypted data is useless without the key.
Without Encryption
- Data readable by anyone with storage access
- Failed audits and compliance violations
- One breach exposes everything
With Encryption
- Data is meaningless without the decryption key
- Meets compliance (HIPAA, PCI-DSS, SOC2)
- Breach = access to ciphertext only
With KMS
- Keys managed centrally and securely
- Automatic rotation and audit trail
- Fine-grained access control on keys
AWS encryption operates in two domains:
Data is encrypted while stored on disk, in databases, or in object storage.
- S3 objects on disk
- EBS volumes
- RDS database files
- DynamoDB tables
Protects: Physical theft, unauthorized disk access, decommissioned hardware
Data is encrypted while moving between systems over a network.
- HTTPS (TLS) for API calls
- TLS between services
- VPN tunnels
- SSH connections
Protects: Eavesdropping, man-in-the-middle, network sniffing
KMS primarily handles encryption at rest. Encryption in transit is handled by TLS/SSL certificates (ACM). They complement each other β a complete system uses both.
A critical mental model shift:
"KMS encrypts my data" β This is technically wrong for most use cases. KMS manages keys, not data. Your data is encrypted locally using a data key that KMS generated and protects.
What KMS actually provides:
- Key generation β creates cryptographic keys inside FIPS 140-2 Level 2 hardware security modules (HSMs)
- Key storage β keys never leave the HSM unencrypted
- Key rotation β automatically rotates keys annually (you keep using the same key ID)
- Access control β key policies + IAM policies determine who can encrypt/decrypt
- Audit trail β every key usage logged in CloudTrail
- Envelope encryption β generates data keys for local encryption (the real workhorse)
- A bank vault holds safety deposit boxes
- The master key is held by the bank manager and never leaves the vault
- You get a copy key to lock your box
- The copy key itself is stored inside the vault (encrypted by master key)
- To use your box: present ID β bank retrieves your copy key β you access data
- KMS = vault (FIPS 140-2 HSMs)
- KMS Key (CMK) = the master key that never leaves KMS
- Data Key = the copy key used to encrypt your actual data
- Encrypted data key stored alongside your ciphertext
- To decrypt: call KMS API β KMS decrypts data key β you decrypt data locally
KMS primarily manages encryption keys, not large data directly. It generates, stores, rotates, and controls access to keys β the actual data encryption happens locally using those keys.
| Concern | Service | Question Answered |
|---|---|---|
| Authentication & Authorization | IAM | WHO can access WHAT resources? |
| Data Protection | KMS | HOW is data protected at rest? |
| Key Access | KMS + IAM | WHO can use encryption keys? |
They work together: IAM might grant you access to an S3 bucket, but if the objects are encrypted with a KMS key you don't have permission to use, you still can't read the data.
| Property | Detail |
|---|---|
| Regional | KMS keys are region-specific. A key in us-east-1 cannot be used in eu-west-1 (unless multi-region key) |
| FIPS 140-2 Level 2 | All keys processed inside validated HSMs β keys never leave unencrypted |
| 4 KB limit | KMS can directly encrypt up to 4 KB of data. For anything larger β envelope encryption |
| Pricing | $1/month per key + $0.03 per 10,000 API calls |
| Key Deletion | 7β30 day waiting period (cannot be undone after deletion) |
| Automatic Rotation | Every 365 days for customer managed keys (opt-in). Key ID stays the same. |
| CloudTrail Integration | Every Encrypt, Decrypt, GenerateDataKey call is logged |
KMS cannot directly encrypt files, database records, or any data larger than 4 KB. This is by design β it forces you to use envelope encryption, which is more secure and performant. This is why Chapter 04 (Envelope Encryption) is the most important chapter in this guide.
- "Encrypt data at rest" β think KMS
- "Encrypt data in transit" β think TLS/ACM
- "Meet compliance for encryption key management" β KMS + CloudTrail audit
- "Regional service" β keys don't replicate by default (multi-region keys are the exception)
- "FIPS 140-2" β KMS uses validated HSMs; CloudHSM uses Level 3 (dedicated)
- "4 KB limit" β forces envelope encryption pattern
- Encryption transforms readable data (plaintext) into unreadable data (ciphertext) using a key.
- At rest = stored data. In transit = data moving on the network.
- KMS manages keys, not data. It generates, stores, rotates, and controls access to encryption keys.
- Keys live inside FIPS 140-2 Level 2 HSMs and never leave unencrypted.
- KMS can only directly encrypt up to 4 KB β larger data uses envelope encryption.
- Every key operation is logged in CloudTrail for audit.
- KMS keys are regional by default.
- IAM controls who can access resources; KMS controls how data is protected.
KMS is not an encryption engine for your data β it's a key management vault. It generates keys, protects them in hardware, controls who can use them, and logs every usage. The actual encryption happens locally using keys KMS provides.
Three AWS services handle encryption-related tasks, but they serve very different purposes:
| Service | Purpose | Key Characteristic | Typical Use Case |
|---|---|---|---|
| KMS | Manage encryption keys for AWS services | Keys never leave HSMs (FIPS 140-2 Level 2) | S3, EBS, RDS encryption at rest |
| CloudHSM | Dedicated, single-tenant HSM | You control the HSM (FIPS 140-2 Level 3) | Regulatory requiring dedicated hardware |
| ACM | Manage TLS/SSL certificates | Automates certificate provisioning & renewal | HTTPS for CloudFront, ALB, API Gateway |
KMS = data at rest encryption. ACM = encryption in transit (TLS certificates). CloudHSM = when you need your own dedicated HSM hardware for regulatory compliance. Example: "Encrypt data in S3 AND terminate HTTPS at ALB" β KMS for S3 + ACM for the TLS certificate.
KMS Core Concepts
KMS has three categories of keys based on who manages them and who owns them. Understanding this distinction is critical for exams and architecture decisions.
AWS Owned Keys
- Managed entirely by AWS
- Shared across many accounts (you never see them)
- Free β no cost
- No CloudTrail logging
- Used by default: DynamoDB, S3 (SSE-S3)
- You cannot view, rotate, or control
AWS Managed Keys
- Created in YOUR account by AWS services
- Named
aws/service-name(e.g.,aws/s3,aws/ebs) - Free (no monthly fee)
- Auto-rotated every year
- Visible in your KMS console
- You cannot change key policy or delete
Customer Managed Keys (CMKs)
- Created and controlled by YOU
- Full control: policies, rotation, deletion
- $1/month per key
- Optional automatic rotation (yearly)
- Cross-account sharing possible
- Can be imported or generated by KMS
Use AWS Managed Keys for simple "enable encryption" cases. Use Customer Managed Keys when you need cross-account access, custom key policies, granular CloudTrail audit, or compliance that requires you to control key lifecycle.
| Feature | AWS Owned | AWS Managed | Customer Managed |
|---|---|---|---|
| Visible in your account | No | Yes | Yes |
| Key policy control | No | No (view only) | Full control |
| Rotation | Varies (AWS decides) | Every year (automatic) | Optional (yearly, on-demand) |
| CloudTrail logging | No | Yes | Yes |
| Cross-account use | No | No | Yes (via key policy) |
| Cost | Free | Free (API charges only) | $1/month + API charges |
| Deletion | Not possible | Not possible | You can schedule (7-30 day wait) |
| Alias | N/A | aws/service-name | Custom alias you define |
When you create a Customer Managed Key, you choose where the key material comes from:
99% of workloads: use KMS-generated key material. Compliance-driven: use External (BYOK) or Custom Key Store. Data sovereignty laws requiring keys outside AWS: External Key Store (XKS).
Every KMS key can be referenced in multiple ways:
1234abcd-12ab-34cd-56ef-1234567890ab. Unique within a region.arn:aws:kms:us-east-1:123456789012:key/1234abcd-... β fully qualified, required for cross-account use.alias/my-app-key β a friendly name. Can be updated to point to a different key (useful for rotation).arn:aws:kms:us-east-1:123456789012:alias/my-app-keyAlways use aliases in application code. When you rotate to a new key, just update the alias β no code change needed. Use Key ARN in cross-account policies.
Aliases decouple your application from specific key versions. This is critical for zero-downtime key rotation:
- Create alias: alias/prod-database-keyPoint it to your current CMK (my-key-v1). All application code references the alias, never the key ID.
- When rotating: create my-key-v2Generate a new CMK alongside the old one. Both exist in parallel.
- Update alias to point to v2Call
UpdateAliasβ the alias now resolves to the new key. Application code doesn't change. - Old key remains for decryptionExisting ciphertext still encrypted with v1. Keep v1 enabled until all data is re-encrypted or expired.
alias/env/service/purpose β e.g., alias/prod/database/encryption, alias/dev/s3/backup, alias/finance/payroll-keyA KMS key goes through distinct states during its lifecycle:
When a KMS key is deleted, all data encrypted by that key becomes permanently unrecoverable. There is no backup, no recovery, no support ticket that can help. The 7-30 day waiting period exists specifically to prevent accidents. Always set up CloudWatch alarms on ScheduleKeyDeletion events.
Rotation replaces the backing key (the actual cryptographic material) while keeping the same Key ID and ARN. Old backing keys are retained forever so old ciphertext can still be decrypted.
- KMS generates new backing key material
- New encryptions use the new backing key
- Old backing keys kept for existing decryptions
- Key ID, ARN, alias β all stay the same
- Zero code changes required
- Automatic: every 365 days (opt-in for CMKs, always on for AWS managed)
- On-demand: trigger rotation manually via API/console
- Manual: create a new key and update your alias to point to it (needed for imported key material)
Key rotation only affects new encryption operations. Existing ciphertext remains encrypted with the old backing key. If compliance requires re-encryption, you must do it yourself (decrypt β re-encrypt with new key).
The key API calls you'll encounter constantly:
| API Call | What It Does | Data Limit |
|---|---|---|
Encrypt | Encrypts up to 4 KB of plaintext directly with a KMS key | 4 KB |
Decrypt | Decrypts ciphertext that was encrypted by KMS | 4 KB |
GenerateDataKey | Returns plaintext data key + encrypted copy. For envelope encryption. | Generates key for any size data |
GenerateDataKeyWithoutPlaintext | Returns ONLY the encrypted data key (for pre-staging) | β |
ReEncrypt | Decrypts ciphertext then re-encrypts under a different key β without exposing plaintext | 4 KB |
CreateGrant | Delegates key permissions to another principal temporarily | β |
GenerateRandom | Returns cryptographically secure random bytes (1-1024 bytes) | 1024 bytes |
Grants are an alternative to key policies for temporary, programmatic permission delegation:
When to Use Grants
- AWS services need temporary key access (e.g., EBS snapshot copy)
- You want to delegate without modifying key policy
- Time-limited access for a specific operation
- Programmatic β created via API, no manual policy edit
Grant Properties
- Grantee Principal: who receives the permission
- Operations: what they can do (Encrypt, Decryptβ¦)
- Constraints: optional conditions (encryption context)
- Retiring Principal: who can revoke the grant
Key policies = permanent, declarative, JSON-based. Grants = temporary, programmatic, API-based. Many AWS services (EBS, RDS) use grants internally when they need key access for specific operations.
Encryption context is a set of key-value pairs (non-secret) that are cryptographically bound to the ciphertext. Think of it as an additional authentication check.
-
Encrypt with context
kms:Encrypt(plaintext, keyId, {"department": "finance", "project": "payroll"}) -
Context is bound to ciphertext
The context is included as Additional Authenticated Data (AAD). It's NOT encrypted β but it IS required for decryption.
-
Decrypt must provide same context
kms:Decrypt(ciphertext, {"department": "finance", "project": "payroll"})β if context doesn't match, decryption FAILS. -
Logged in CloudTrail
Encryption context appears in CloudTrail logs β perfect for auditing WHO encrypted WHAT for WHICH purpose.
It prevents ciphertext from being used out of context. Even if an attacker has the ciphertext AND decrypt permissions, they must know the exact encryption context. It's also valuable for CloudTrail audit β you can see what was encrypted, not just that encryption happened.
Encryption context is cryptographically bound to the ciphertext AND logged in CloudTrail. Here's how production teams use it:
Multi-Tenant SaaS
{"tenantId": "tenant-12345", "customerId": "cust-67890"}
- CloudTrail shows which tenant's data accessed
- Prevents cross-tenant decryption
- Same CMK shared across tenants
Environment Isolation
{"environment": "production", "service": "payment"}
- Same CMK for dev/prod
- Context prevents prod keys in dev
- Key policy condition enforces
Healthcare Compliance
{"patientId": "PAT-456", "recordType": "medical-history"}
- Complete audit trail per patient
- WHO accessed WHICH data
- HIPAA compliance evidence
S3 Automatic Context
{"aws:s3:arn": "arn:aws:s3:::bucket/key"}
- S3 adds this automatically (SSE-KMS)
- CloudTrail shows exact object
- Reduced with S3 Bucket Keys (bucket ARN instead)
Always include at least one context key-value pair. It costs nothing, adds zero latency, and dramatically improves auditability. Use it for tenant isolation, environment separation, and compliance evidence.
When creating a KMS key, you specify what it can do:
| Key Usage | Description | Key Specs Available |
|---|---|---|
| ENCRYPT_DECRYPT | Symmetric encryption. Most common β used by all AWS service integrations. | SYMMETRIC_DEFAULT (AES-256-GCM) |
| SIGN_VERIFY | Digital signatures. Asymmetric only. | RSA_2048..4096, ECC_NIST_P256..P521, SM2 |
| GENERATE_VERIFY_MAC | HMAC operations. | HMAC_224..512 |
| KEY_AGREEMENT | Derive shared secrets (ECDH). New in 2024. | ECC_NIST_P256..P521, SM2 |
Once you create a key with a specific usage (e.g., ENCRYPT_DECRYPT), you cannot change it. You'd need to create a new key. Plan your key strategy upfront.
By default, KMS keys are regional. Multi-Region keys are replicas of the same key in multiple regions β same key material, same key ID (with mrk- prefix).
Use Cases
- Encrypt in one region, decrypt in another
- DynamoDB global tables with encryption
- S3 cross-region replication of encrypted objects
- Disaster recovery β decrypt in failover region
Not Recommended When
- Data residency laws require separate keys per region
- You want independent key policies per region
- Simple single-region workloads (adds complexity)
- You need different key material per region
- "Cannot change key policy" β AWS Managed Key. Need control? Use Customer Managed Key.
- "Cross-account encryption" β must use Customer Managed Key + key policy granting access
- "Key never leaves AWS" β KMS default. "Key material outside AWS" β External Key Store (XKS)
- "FIPS 140-2 Level 3" β CloudHSM (not KMS). KMS is Level 2.
- "Encrypt in us-east-1, decrypt in eu-west-1" β Multi-Region Key
- "Scheduled deletion" β 7-30 days waiting period. Can be cancelled.
- "Rotation doesn't re-encrypt data" β correct. Old backing key retained for old ciphertext.
- "Encryption context" β required at decrypt time if provided at encrypt time. Logged in CloudTrail.
GenerateDataKeyβ envelope encryption (data > 4 KB).Encryptβ direct (β€ 4 KB).
- Three key types: AWS Owned (invisible, free), AWS Managed (visible, no control), Customer Managed (full control, $1/mo).
- Key material origin: KMS-generated (default), External (BYOK), Custom Key Store (CloudHSM), External Key Store (XKS).
- Key identifiers: Key ID, Key ARN, Alias Name, Alias ARN. Use aliases in code.
- Key states: Enabled β Disabled β Pending Deletion β Deleted (irreversible).
- Key rotation: replaces backing material, retains old for decryption, same Key ID.
- API operations: Encrypt (β€4KB), Decrypt, GenerateDataKey, ReEncrypt, CreateGrant.
- Grants: temporary, programmatic key permission delegation (used by AWS services internally).
- Encryption context: key-value pairs bound to ciphertext β must match at decrypt time.
- Multi-Region keys: same key material across regions β encrypt anywhere, decrypt anywhere.
Customer Managed Keys give you full control over policies, rotation, and cross-account access. Every key has a lifecycle (enabled β deleted), and deletion is irreversible. Use aliases for flexibility, encryption context for audit, and understand that rotation only affects new encryptions.
KMS supports two fundamental cryptographic key types β symmetric (one shared secret) and asymmetric (public + private key pair). Understanding when and why to choose each is critical for every AWS architecture decision.
A symmetric KMS key generates a single 256-bit AES-GCM key. The same key encrypts and decrypts data. The plaintext key never leaves KMS unencrypted β all encrypt/decrypt operations happen inside the HSM boundary.
How Symmetric Works
- One key β used for both encrypt & decrypt
- AES-256-GCM algorithm
- Key material stays in HSM hardware
- Encrypt up to 4 KB directly via API
- For larger data β envelope encryption (Ch04)
When to Use Symmetric
- Encrypting data at rest (S3, EBS, RDS, DynamoDB)
- All AWS service integrations (default)
- Envelope encryption with data keys
- When both encrypt/decrypt happen inside AWS
- Highest performance & lowest cost
Every KMS key you create is symmetric by default. Over 99% of AWS service integrations use symmetric keys β if you're unsure, choose symmetric.
An asymmetric KMS key creates a mathematically linked pair: a private key (stays in HSM) and a public key (downloadable). Different algorithms serve different purposes.
| Key Spec | Algorithm | Use Case | Max Data Size |
|---|---|---|---|
| RSA_2048 | RSAES_OAEP_SHA_256 | Encrypt / Decrypt | 214 bytes |
| RSA_3072 | RSAES_OAEP_SHA_256 | Encrypt / Decrypt | 342 bytes |
| RSA_4096 | RSAES_OAEP_SHA_256 | Encrypt / Decrypt | 470 bytes |
| RSA_2048 | RSASSA_PSS / PKCS1 | Sign / Verify | β |
| ECC_NIST_P256 | ECDSA_SHA_256 | Sign / Verify | β |
| ECC_NIST_P384 | ECDSA_SHA_384 | Sign / Verify | β |
| ECC_NIST_P521 | ECDSA_SHA_512 | Sign / Verify | β |
| ECC_SECG_P256K1 | ECDSA_SHA_256 | Sign / Verify (blockchain) | β |
| SM2 (China) | SM2DSA / SM2PKE | Sign or Encrypt | β |
Asymmetric for Encryption
- Public key encrypts (anyone can)
- Private key decrypts (only KMS)
- Useful when encryptor has no AWS credentials
- External clients, IoT devices, mobile apps
- Limited by RSA max data size
Asymmetric for Signing
- Private key signs (KMS does this)
- Public key verifies (anyone can)
- JWT tokens, code signing, document signing
- External verification without AWS API calls
- ECC preferred for performance; RSA for compatibility
When creating an asymmetric key, you must choose its KeyUsage. A key can only be used for one purpose β this is immutable after creation.
KeyUsage and KeySpec are set at creation and cannot be changed. If you need encryption AND signing, you need two separate keys.
KMS supports symmetric HMAC keys for generating and verifying Hash-based Message Authentication Codes. Unlike encryption, HMAC doesn't hide data β it proves integrity and authenticity.
HMAC_SHA_256
- 256-bit key
- Most common choice
- API token validation
HMAC_SHA_384
- 384-bit key
- Higher security margin
- Financial protocols
HMAC_SHA_512
- 512-bit key
- Maximum security
- Critical system integrity
Use cases for KMS HMAC: validating API tokens, verifying webhook signatures, secure session cookies, license key validation β anywhere you need "was this data produced by someone who has the key?" without encrypting the data itself.
| Scenario | Key Type | Key Spec | Why |
|---|---|---|---|
| S3 server-side encryption | Symmetric | SYMMETRIC_DEFAULT | AWS service integration β only option |
| EBS volume encryption | Symmetric | SYMMETRIC_DEFAULT | Data at rest β envelope encryption |
| IoT device sending encrypted data | Asymmetric | RSA_2048 | Device has public key, no AWS creds |
| JWT token signing (Lambda) | Asymmetric | ECC_NIST_P256 | Fast signing, external verification |
| Code artifact signing | Asymmetric | RSA_4096 | Wide compatibility, strong security |
| API webhook validation | HMAC | HMAC_SHA_256 | Prove origin without encryption |
| Cross-account data sharing | Symmetric | SYMMETRIC_DEFAULT | Grant decrypt access to other account |
| Blockchain transaction signing | Asymmetric | ECC_SECG_P256K1 | secp256k1 standard for crypto chains |
| TLS certificate private key | Asymmetric | RSA_2048 | ACM integration with custom key store |
A common production pattern combines symmetric keys for bulk encryption with asymmetric keys for signing artifacts:
- Build system produces artifactCI/CD pipeline compiles code, generates container image or deployment package.
- Sign artifact hash with asymmetric keyCall
kms:Signwith artifact SHA-256 digest. KMS uses private ECC/RSA key inside HSM. - Store artifact + signatureUpload artifact to S3 (encrypted with symmetric CMK via SSE-KMS) and attach signature as metadata.
- Consumer downloads & verifiesDeployment system downloads artifact, retrieves public key, verifies signature locally β no KMS API call needed.
- Deploy with confidenceVerified artifact is decrypted (KMS Decrypt via IAM role) and deployed. Tamper-proof supply chain.
Asymmetric Limitations
- Cannot use with AWS service integrations (S3, EBS, RDS)
- RSA encryption limited to small payloads (214β470 bytes)
- No automatic key rotation (must manually create new key)
- Cannot generate data keys (no
GenerateDataKey) - Cannot use encryption context
- Higher API latency than symmetric operations
Symmetric Limitations
- Plaintext key never exported β both sides need KMS access
- Cannot be used for digital signatures
- Public key concept doesn't exist
- Direct encrypt limited to 4 KB
- Cross-region: must re-encrypt or use multi-region keys
- "External party needs to encrypt" β Asymmetric RSA (public key distributed, no AWS creds needed)
- "AWS service encryption (S3, EBS, RDS)" β Always symmetric. Asymmetric keys CANNOT integrate.
- "Verify signature without AWS access" β Asymmetric (download public key, verify locally)
- "Rotate asymmetric key" β Manual process. Create new key, distribute new public key, retire old.
- "HMAC" in question β Symmetric HMAC key,
GENERATE_VERIFY_MACusage. - "Envelope encryption" β Symmetric only.
GenerateDataKeynot available for asymmetric. - "Encrypt large data outside AWS" β Hybrid: use asymmetric to encrypt a symmetric data key, then use AES locally.
Symmetric key = a shared safe combination. Both parties must know the combo (have KMS access).
Asymmetric key = a padlock. Anyone can lock it (public key), but only the owner has the key to open it (private key in HSM).
Symmetric: both encrypt-side and decrypt-side call KMS API (need IAM permissions).
Asymmetric: encrypt-side uses downloaded public key (no AWS needed); decrypt-side calls KMS (private key never leaves).
- Symmetric (AES-256): One key, both sides need KMS access. Default for all AWS service integrations. Fast, cheap, supports envelope encryption.
- Asymmetric (RSA/ECC): Key pair β public (downloadable) + private (HSM-locked). Use when external parties participate.
- KeyUsage is immutable: ENCRYPT_DECRYPT, SIGN_VERIFY, GENERATE_VERIFY_MAC, or KEY_AGREEMENT. One key = one purpose.
- HMAC keys: Symmetric keys for message authentication β prove integrity without encryption.
- Asymmetric rotation: Manual only. Must create new key and redistribute public key.
- ECC vs RSA: ECC = smaller/faster signatures; RSA = wider compatibility + encryption support.
- AWS services (S3, EBS, RDS): Only symmetric keys work. No exceptions.
- Hybrid pattern: Asymmetric to protect a symmetric data key β AES encrypts bulk data locally.
Choose symmetric for AWS-native encryption (99% of cases). Choose asymmetric when an external party must encrypt or verify without AWS credentials. The decision is permanent β KeyUsage and KeySpec cannot be changed after creation.
Envelope encryption is the single most important concept in KMS. It's how AWS encrypts terabytes of data while only using KMS for a tiny 256-bit key. Master this and you understand every AWS encryption integration.
KMS can only encrypt up to 4 KB directly. Every real-world workload (files, databases, volumes) uses envelope encryption β encrypting a data key with KMS, then using that data key locally. This is not optional knowledge β it's foundational.
If KMS can only encrypt 4 KB at a time, how does AWS encrypt a 1 TB EBS volume? Sending every block to KMS would be:
Impossibly Slow
- Network round-trip per 4 KB block
- 1 TB = 262 million API calls
- Days to encrypt a single volume
Absurdly Expensive
- $0.03 per 10,000 requests
- 262M calls = $786 per volume
- Multiply by hundreds of volumes
Rate Limited
- KMS quota: 5,500β30,000 req/sec
- Would throttle instantly
- All other apps blocked too
The solution: Don't send the data to KMS. Instead, ask KMS for a key, then encrypt the data locally. This is envelope encryption.
- GenerateDataKeyYour app calls
kms:GenerateDataKeywith a CMK ID. KMS returns TWO things: a plaintext data key + an encrypted copy of that same key. - Encrypt data locallyUse the plaintext data key with AES-256 to encrypt your file/volume/database locally β no network call, no size limit, blazing fast.
- Discard plaintext key from memoryImmediately delete the plaintext data key. It existed only for the duration of the encrypt operation. Zero it out.
- Store encrypted key alongside dataStore the encrypted data key (the "envelope") with the ciphertext. It's safe β the encrypted key is useless without KMS.
- Decrypt: retrieve encrypted key β call KMSTo decrypt, read the encrypted data key, call
kms:Decryptto get the plaintext key back, then decrypt locally.
| API | Returns Plaintext? | When to Use |
|---|---|---|
| GenerateDataKey | Yes β plaintext + encrypted copy | When you need to encrypt data immediately |
| GenerateDataKeyWithoutPlaintext | No β encrypted copy only | When you'll encrypt later (pre-generate keys, store for future use) |
GenerateDataKeyWithoutPlaintext is used when you want to prepare encrypted data keys in advance. For example, a key management system generates keys for future messages β the plaintext key is only recovered (via kms:Decrypt) when actually needed.
Both APIs create the SAME data key. The difference is only whether KMS returns the plaintext immediately or keeps it hidden until you explicitly decrypt the encrypted copy later.
Imagine putting a letter (your data) inside an envelope.
The envelope is sealed with a wax stamp (the data key).
The wax stamp itself is locked in a safe (encrypted by the CMK).
To read the letter: open the safe β get the stamp β open the envelope.
- Letter = your data (any size)
- Envelope seal = data key (AES-256)
- Safe = CMK in KMS HSM
- Opening the safe =
kms:Decryptcall - Only KMS can open that safe
AWS services often use multiple layers of envelope encryption for performance and key management:
S3 Bucket Keys are the most important optimization for SSE-KMS at scale:
| Aspect | Without Bucket Key | With Bucket Key |
|---|---|---|
| KMS calls per object | 1 GenerateDataKey per PUT | 1 call per bucket key rotation (~few minutes) |
| Cost (1M objects/day) | ~$3/day in KMS charges | ~$0.01/day |
| CloudTrail events | 1 per object operation | 1 per bucket key generation |
| Throttling risk | High at scale | Virtually eliminated |
| Encryption context | Object ARN | Bucket ARN (less granular) |
Always enable S3 Bucket Keys for SSE-KMS buckets. It reduces KMS costs by up to 99% and eliminates throttling at scale. The only trade-off: CloudTrail shows the bucket ARN instead of individual object ARNs in KMS events.
The AWS Encryption SDK supports data key caching β reusing a data key for multiple encrypt operations instead of calling GenerateDataKey every time.
Benefits
- Reduces KMS API calls dramatically
- Lower latency (no network round-trip)
- Avoids KMS throttling
- Reduces cost for high-throughput apps
Trade-offs
- Same key encrypts multiple messages
- Larger blast radius if key compromised
- Must set max age, max bytes, max messages
- Not suitable for highest-security workloads
| Service | Data Key Scope | Key Hierarchy |
|---|---|---|
| S3 (SSE-KMS) | Per object (or bucket key) | CMK β Bucket Key β Object Key β Object |
| EBS | Per volume | CMK β Volume Key β Each I/O block |
| RDS | Per instance | CMK β Instance Key β Tablespace files |
| DynamoDB | Per table | CMK β Table Key β Per-item encryption |
| Lambda (env vars) | Per function version | CMK β Function Key β Environment variables |
| Secrets Manager | Per secret version | CMK β Data Key β Secret value |
| EFS | Per file system | CMK β FS Key β Per-file data key |
What Envelope Encryption Gives You
- Separation of duties: admin of CMK β user of data
- Blast radius reduction: each object has unique key
- Audit trail: every key usage logged in CloudTrail
- Centralized revocation: disable CMK β all data inaccessible
- Performance: local encryption at hardware speed
Critical Insight
- Deleting a CMK = permanent data loss
- All data keys encrypted by that CMK become undecryptable
- 7β30 day waiting period exists for this reason
- No recovery possible β AWS cannot help
- This is why key policies matter so much
- "Encrypt large files with KMS" β Envelope encryption.
GenerateDataKeyβ local AES encrypt. - "4 KB limit" β Direct KMS Encrypt API limit. For anything larger β envelope encryption.
- "Reduce KMS costs for S3" β Enable S3 Bucket Keys (reduces calls by 99%).
- "KMS throttling" β Use data key caching, S3 bucket keys, or request quota increase.
- "How does EBS encryption work?" β KMS decrypts volume key once at attach; Nitro card encrypts all I/O in hardware.
- "What if CMK is deleted?" β All data encrypted by data keys from that CMK is permanently lost.
- "GenerateDataKeyWithoutPlaintext" β Pre-generate encrypted keys for later use (message queuing, batch processing).
- The pattern: GenerateDataKey β encrypt locally β discard plaintext key β store encrypted key with data.
- Why: KMS 4 KB limit + performance + cost. Real data never leaves your environment.
- Two API calls total: GenerateDataKey (encrypt) + Decrypt (decrypt). That's it.
- Multi-layer: CMK β Bucket/Volume Key β Object/Block Key β Data. Each layer limits blast radius.
- S3 Bucket Keys: Cache intermediate key, reduce KMS calls 99%, always enable for SSE-KMS.
- Data Key Caching: AWS Encryption SDK feature. Reuse keys with max age/messages/bytes limits.
- EBS: KMS decrypts volume key once β Nitro card handles all I/O encryption in hardware.
- CMK deletion = permanent data loss. 7β30 day waiting period is your safety net.
Envelope encryption is THE mechanism that makes KMS practical. KMS protects a small data key; that data key protects terabytes of data locally. Only 2 API calls needed regardless of data size. Deleting the CMK makes ALL data it protected permanently unrecoverable.
KMS has its own authorization model that is different from standard IAM. Every KMS key has a key policy β a resource-based policy that is the primary access control mechanism. Without it, even the root account can be locked out.
Unlike S3 or Lambda, a KMS key policy is mandatory. If no key policy explicitly grants access, IAM policies alone are insufficient. The key policy must either grant access directly OR enable IAM policies to grant access.
Every KMS key has exactly one key policy (up to 32 KB). It determines who can use and manage the key. The default key policy contains one critical statement:
The Default Key Policy Statement
- Effect: Allow
- Principal: arn:aws:iam::ACCOUNT-ID:root
- Action: kms:*
- Resource: * (this key)
This statement does NOT grant access to the root user directly. It enables IAM policies in the account to grant KMS permissions. Without this statement, IAM policies are ignored for this key.
The root principal statement is a delegation β it says "I trust this account's IAM system to manage access." Remove it, and ONLY explicit key policy statements control access. This is how keys get permanently locked.
Access to a KMS key is the union of three layers (all must align for access to be granted):
Layer 1: Key Policy
- Resource-based policy on the key itself
- Always evaluated (cannot be bypassed)
- Must explicitly allow OR delegate to IAM
- 32 KB maximum size
Layer 2: IAM Policies
- Identity-based (attached to user/role)
- Only works IF key policy enables IAM
- Standard IAM Allow/Deny rules
- Supports conditions, resource ARNs
Layer 3: Grants
- Temporary, programmatic permissions
- Created by key users for delegation
- Used by AWS services internally
- Can be revoked instantly
| Statement Purpose | Principal | Actions | Why |
|---|---|---|---|
| Enable IAM | arn:aws:iam::ACCT:root | kms:* | Lets IAM policies manage access (default) |
| Key Administrator | arn:aws:iam::ACCT:role/Admin | kms:Create*, kms:Describe*, kms:Enable*, kms:List*, kms:Put*, kms:Update*, kms:Revoke*, kms:Disable*, kms:Delete*, kms:Tag*, kms:UntagResource, kms:ScheduleKeyDeletion, kms:CancelKeyDeletion | Manage key lifecycle (cannot use for crypto) |
| Key User | arn:aws:iam::ACCT:role/AppRole | kms:Encrypt, kms:Decrypt, kms:ReEncrypt*, kms:GenerateDataKey*, kms:DescribeKey | Use key for cryptographic operations |
| Grant Delegation | arn:aws:iam::ACCT:role/AppRole | kms:CreateGrant, kms:ListGrants, kms:RevokeGrant | Allow role to delegate access to AWS services |
| Cross-Account | arn:aws:iam::OTHER-ACCT:root | kms:Encrypt, kms:Decrypt, kms:GenerateDataKey*, kms:DescribeKey | Allow other account to use key (they also need IAM policy) |
A critical security pattern: the person who manages a key should NOT be the person who uses it for encryption:
- Can enable/disable the key
- Can modify key policy
- Can schedule deletion
- Can tag and describe
- Cannot encrypt or decrypt
- Can encrypt and decrypt
- Can generate data keys
- Can create grants for services
- Cannot modify key policy
- Cannot delete the key
In regulated environments, ensure no single principal has both kms:PutKeyPolicy and kms:Decrypt. This prevents a compromised admin from both accessing data and covering their tracks.
Sharing a KMS key across accounts requires both sides to grant permission:
- Key policy in Account A (key owner)Add a statement allowing
arn:aws:iam::ACCOUNT-B:rootto use the key (kms:Encrypt, kms:Decrypt, kms:GenerateDataKey*, kms:DescribeKey). - IAM policy in Account B (key user)Attach an IAM policy to the role/user in Account B allowing the same KMS actions on the key ARN in Account A.
- Both must alignMissing either side = access denied. This is the same dual-authorization model as S3 cross-account access.
Instead of modifying the key policy, Account A can create a grant for a specific principal in Account B. Grants are more temporary and don't require key policy changes β useful for automated cross-account workflows.
Grants provide temporary, scoped access to a KMS key without modifying the key policy. AWS services use grants internally when you select "encrypt with CMK":
When AWS Uses Grants
- EBS creating an encrypted volume
- RDS encrypting a database instance
- Lambda decrypting environment variables
- Secrets Manager accessing secrets
- Any service needing temporary key access
Grant Lifecycle
CreateGrantβ issue new grant- Grant token β use immediately (before replication)
ListGrantsβ view active grantsRetireGrantβ grantee removes own grantRevokeGrantβ admin revokes any grant
KMS supports powerful condition keys for both key policies and IAM policies:
| Condition Key | Controls | Example Use |
|---|---|---|
| kms:ViaService | Which AWS service is making the call | Allow only S3 to use this key |
| kms:CallerAccount | AWS account of the caller | Restrict cross-account usage |
| kms:EncryptionContext:key | Require specific encryption context | Only decrypt if context matches |
| kms:GrantIsForAWSResource | Grant must be for AWS service use | Prevent grants to arbitrary principals |
| kms:KeyOrigin | Where key material came from | Only allow KMS-generated keys |
| kms:KeySpec | Key algorithm specification | Only allow symmetric keys |
| kms:RequestAlias | Alias used in request | ABAC β control by alias name pattern |
| aws:SourceVpce | VPC endpoint ID | Only allow from specific VPC endpoint |
Use kms:ViaService to ensure a key can only be used through specific AWS services. Example: allow the key for S3 encryption but prevent direct kms:Encrypt calls. This prevents data exfiltration through direct KMS API usage.
Lockout Scenario 1
- Remove root account from key policy
- Remove all admins from key policy
- Now NO ONE can modify the key policy
- Key becomes permanently unusable
- Fix: Contact AWS Support (they can reset)
Lockout Scenario 2
- Key policy grants access to a specific role
- That role is deleted from IAM
- No other principal in key policy
- Root statement was removed
- Fix: AWS Support only (cannot self-recover)
Never remove the root account statement from a key policy unless you have a deliberate reason and another explicit principal that can manage the key. Always test key policy changes in a non-production key first.
- "IAM policy alone doesn't work for KMS" β Key policy must enable IAM OR directly allow the principal.
- "Cross-account KMS" β Need BOTH: key policy in owner account + IAM policy in user account.
- "Restrict key to S3 only" β Use condition
kms:ViaService: s3.*.amazonaws.com. - "Key is locked, no one can access" β Contact AWS Support. They can reset the key policy (only for account root).
- "Temporary access to KMS key" β Use Grants. No key policy change needed.
- "Who can delete vs who can encrypt" β Separation of duties. Key admin β Key user.
- "Prevent direct KMS API calls" β Use
kms:ViaServicecondition + VPC endpoint policy. - "ABAC for KMS" β Use
kms:RequestAliasor resource tags withaws:ResourceTagconditions.
- Key policy is mandatory: Unlike other AWS services, IAM alone cannot grant KMS access. Key policy must allow or delegate.
- Default root statement: Enables IAM policies. Remove it β only explicit key policy principals can access.
- Three layers: Key Policy + IAM Policies + Grants. Access = union of all three (minus explicit denies).
- Separation of duties: Key admins (manage lifecycle) vs Key users (encrypt/decrypt). Never combine in production.
- Cross-account: Key policy (owner) + IAM policy (user). Both required.
- Grants: Temporary programmatic access. AWS services use them internally. Can be revoked instantly.
- Condition keys: kms:ViaService, kms:EncryptionContext, kms:CallerAccount for fine-grained control.
- Lockout prevention: Never remove root statement without another admin. AWS Support is last resort.
KMS access requires the key policy to say "yes" first. Without a key policy statement (direct or delegated), IAM policies are powerless. Cross-account needs both sides. Grants provide temporary access without policy changes. One wrong key policy edit can permanently lock a key.
| Error | Symptom | Common Cause | Fix |
|---|---|---|---|
| AccessDeniedException | "User is not authorized to perform kms:Decrypt" | Key policy missing IAM delegation OR IAM policy missing kms: action | Add root account to key policy + kms:Decrypt to IAM policy |
| ValidationException | "Ciphertext is larger than 4096 bytes" | Direct Encrypt API called with >4 KB data | Use GenerateDataKey + local AES encryption (envelope encryption) |
| ThrottlingException | "Rate exceeded" / "Request was throttled" | Exceeded regional KMS quota | S3 Bucket Keys, data key caching, request quota increase |
| NotFoundException | "Key ARN does not exist" | Wrong region, deleted key, or typo in ARN | Verify region (keys are regional). Check key state. Use correct ARN format. |
| InvalidKeyUsageException | "Operation not supported for this key usage" | Asymmetric key used for symmetric op (or vice versa) | Check KeySpec. Create separate keys for different purposes. |
| DependencyTimeoutException | "Custom key store is unavailable" | CloudHSM cluster unreachable | Check CloudHSM health. Ensure kmsuser logged in. Verify VPC connectivity. |
| KMSInvalidStateException | "Key is pending deletion/disabled" | Key was disabled or scheduled for deletion | EnableKey or CancelKeyDeletion if within waiting period |
For AccessDenied: check three things in order β (1) Key Policy allows principal or delegates to IAM, (2) IAM policy includes kms: actions on the key ARN, (3) No explicit Deny in any SCP, boundary, or policy. Use IAM Policy Simulator and CloudTrail to pinpoint the failure.
KMS integrates with 100+ AWS services. Understanding how each service uses KMS β what encryption options exist, what permissions are needed, and what CloudTrail events are generated β is essential for both architecture and security.
| Option | Key Management | Who Manages Key | Cost | Audit (CloudTrail) |
|---|---|---|---|---|
| SSE-S3 | AES-256, S3-managed | AWS (invisible) | Free | No KMS events |
| SSE-KMS | KMS CMK | You (key policy) | $1/mo + API calls | Full audit trail |
| SSE-KMS + Bucket Key | KMS CMK + cached key | You (key policy) | $1/mo + minimal API | Reduced granularity |
| SSE-C | Customer-provided key | You (full lifecycle) | Free | No KMS events |
| DSSE-KMS | Dual-layer KMS encryption | You (key policy) | $1/mo + API calls | Full audit trail |
When to Choose SSE-KMS
- Need audit trail of every access
- Need to control who can decrypt
- Regulatory/compliance requirement
- Cross-account data sharing with control
- Need to revoke access centrally
S3 + KMS Permissions Needed
kms:GenerateDataKeyβ for PutObjectkms:Decryptβ for GetObjectkms:DescribeKeyβ key validation- Key policy OR IAM + grant must allow
- Bucket policy alone is NOT enough
Granting s3:GetObject without kms:Decrypt results in Access Denied for SSE-KMS objects. The principal needs BOTH S3 permissions AND KMS permissions on the specific key.
EC2 instance needs: IAM role with kms:CreateGrant + kms:Decrypt + kms:DescribeKey + kms:GenerateDataKeyWithoutPlaintext. EBS internally creates a grant to decrypt the volume key at attach time.
What's Encrypted
- DB storage (data files)
- Automated backups
- Read replicas
- Snapshots
- Logs (if enabled)
Limitations
- Cannot encrypt existing unencrypted DB
- Must snapshot β copy with encryption β restore
- Read replica must use same or different CMK (same region = same; cross-region = different)
- Cannot change CMK after creation
| Option | Key | Cost | Rotation | Control |
|---|---|---|---|---|
| AWS Owned (default) | AWS-managed, invisible | Free | Automatic (varies) | None |
| AWS Managed (aws/dynamodb) | Visible in KMS console | Free | Yearly (automatic) | View only |
| Customer Managed | Your CMK | $1/mo + usage | Configurable | Full (policy, disable, delete) |
Key point: DynamoDB encryption is always on β you only choose which key type. Client-side encryption (using the DynamoDB Encryption Client) adds field-level encryption on top.
Lambda
- Environment variables encrypted at rest
- Default: AWS managed key (aws/lambda)
- Optional: CMK for additional control
- Helpers for decrypt in function code
- Grant created at deploy time
Secrets Manager
- Each secret version encrypted with data key
- Default: aws/secretsmanager key
- CMK for cross-account secret sharing
- Automatic rotation built-in
- kms:Decrypt needed to retrieve secret
SSM Parameter Store
- SecureString type uses KMS
- Standard: aws/ssm default key
- Advanced: custom CMK
- kms:Decrypt on the key required
- Free tier: 10,000 standard params
Every KMS API call is logged in CloudTrail. This provides a complete audit trail of who accessed which key, when, and from which service:
| Event Field | What It Shows | Example Value |
|---|---|---|
| eventName | KMS API action | Decrypt, GenerateDataKey |
| userIdentity | Who made the call | Role ARN, assumed-role session |
| requestParameters.keyId | Which key was used | Key ARN or alias |
| requestParameters.encryptionContext | Context key-value pairs | aws:s3:arn, aws:ebs:id |
| sourceIPAddress | Caller origin | IP or service name (e.g., s3.amazonaws.com) |
| vpcEndpointId | VPC endpoint used | vpce-0abc123... |
Set up CloudWatch alarms for: unusual Decrypt volume, key policy changes (PutKeyPolicy), DisableKey, ScheduleKeyDeletion, and failed access attempts. These are early indicators of compromise or misconfiguration.
SQS + KMS
- Server-side encryption (SSE-KMS)
- Messages encrypted at rest
- Producer needs kms:GenerateDataKey
- Consumer needs kms:Decrypt
- Data key cached for reuse period
SNS + KMS
- Topic encryption with CMK
- Publisher needs kms:GenerateDataKey
- Subscribers (SQS, Lambda) need kms:Decrypt
- Cross-account: key policy must allow subscriber
- HTTPS endpoints receive decrypted
Kinesis + KMS
- Stream-level encryption
- Each shard gets data keys
- Producer: kms:GenerateDataKey
- Consumer: kms:Decrypt
- High throughput = watch KMS quotas
| Operation Type | Default Quota (per second) | Increasable? | Applies To |
|---|---|---|---|
| Cryptographic operations (symmetric) | 5,500 β 30,000 (varies by region) | Yes (via Support) | Encrypt, Decrypt, GenerateDataKey, ReEncrypt |
| Cryptographic operations (asymmetric RSA) | 500 | Yes | RSA Sign, Encrypt, Decrypt |
| Cryptographic operations (asymmetric ECC) | 300 | Yes | ECC Sign |
| Management operations | 5 β 50 | No | CreateKey, PutKeyPolicy, ScheduleKeyDeletion |
What happens when exceeded: KMS returns ThrottlingException. AWS SDKs automatically implement exponential backoff with jitter. Set CloudWatch alarm on ThrottledRequests metric at >100/minute.
π‘οΈ Throttling Mitigation
- Enable S3 Bucket Keys (biggest impact)
- Use data key caching (Encryption SDK)
- Request quota increase via Support
- Distribute across multiple CMKs
- Use exponential backoff + jitter
π Monitoring
- CloudWatch:
ThrottledRequestsmetric - CloudWatch:
SecondsUntilKeyMaterialExpiration - AWS Trusted Advisor: KMS quota check
- Service Quotas dashboard
- Set alarms at 80% utilization
- "AccessDenied on S3 GetObject" β Check if object is SSE-KMS encrypted. Principal needs
kms:Decrypton that key. - "Share encrypted EBS snapshot cross-account" β Share snapshot + grant key access OR copy with recipient's own key.
- "Encrypt existing unencrypted RDS" β Snapshot β Copy with encryption β Restore from encrypted snapshot.
- "Reduce KMS costs for S3 at scale" β Enable S3 Bucket Keys.
- "KMS ThrottlingException" β Data key caching, bucket keys, or request quota increase.
- "DynamoDB encryption" β Always encrypted. Choose between AWS owned (free, no control), AWS managed, or CMK.
- "Lambda env var encryption" β Default uses aws/lambda. Use CMK for cross-account or policy control.
- "SQS cross-account with CMK" β Key policy must allow producing account's role to call kms:GenerateDataKey.
- S3 SSE-KMS: GenerateDataKey on PUT, Decrypt on GET. Use Bucket Keys for cost. Missing kms: permission = AccessDenied.
- EBS: Volume key decrypted once at attach (Nitro card). Cannot encrypt in-place. Snapshot sharing needs key access.
- RDS/Aurora: Encryption at creation only. Snapshot β copy encrypted β restore for existing DBs.
- DynamoDB: Always encrypted. Three key options: AWS owned, AWS managed, Customer managed.
- Lambda/Secrets/SSM: Env vars, secrets, SecureStrings all use envelope encryption via KMS.
- SQS/SNS/Kinesis: Message encryption at rest. Producer needs GenerateDataKey, consumer needs Decrypt.
- CloudTrail: Every KMS API call logged. Monitor for unusual patterns, policy changes, deletions.
- Quotas: 5,500β30,000 req/sec symmetric. Mitigate with caching, bucket keys, quota increases.
| Component | Cost | Notes |
|---|---|---|
| Customer Managed Key (CMK) | $1/month per key | Charged even when not in use |
| AWS Managed Key | $0 (free) | No monthly fee, only API charges |
| API calls (Encrypt, Decrypt, GenerateDataKey) | $0.03 per 10,000 requests | Biggest cost driver at scale |
| S3 Bucket Keys | $0 | Free feature that reduces API costs 99% |
Typical monthly costs by workload:
| Workload | Without Optimization | With Optimization | Strategy |
|---|---|---|---|
| S3 bucket (1M objects/day, SSE-KMS) | ~$90/month | ~$1/month | Enable Bucket Keys |
| 100 EBS volumes + daily snapshots | ~$104/month | ~$100/month | Consolidate CMKs |
| Lambda (10M invocations, env vars encrypted) | ~$30/month | ~$30/month | Use AWS managed key if no cross-account need |
| High-throughput messaging (100K msg/sec) | ~$26K/month | ~$50/month | Data key caching + reuse period |
Deleting a CMK removes the $1/month fee but makes all data encrypted with it permanently unrecoverable. Never delete a CMK without confirming full data migration or intentional erasure.
Every AWS encryption integration follows the same pattern: service calls GenerateDataKey or Decrypt on your behalf using grants. You need both service permissions AND KMS permissions. Missing either = AccessDenied. S3 Bucket Keys and data key caching solve scale/cost problems.
Beyond standard KMS usage, AWS offers advanced key management options for organizations with strict compliance, data sovereignty, or hybrid-cloud requirements. These options trade convenience for greater control.
A Custom Key Store connects KMS to your own AWS CloudHSM cluster. Key material is generated and stored in HSMs you control β not in the shared KMS HSM fleet.
When to Use Custom Key Store
- Regulatory requirement for single-tenant HSM
- Need FIPS 140-2 Level 3 (KMS default is Level 2)
- Must have direct control over HSM hardware
- Compliance mandates key isolation
- Organization requires explicit HSM audit logs
Trade-offs
- CloudHSM cluster cost (~$1.50/hr per HSM)
- You manage HSM availability (min 2 HSMs)
- Lower performance than standard KMS
- More complex setup and maintenance
- Key operations fail if HSM cluster is down
- Create CloudHSM ClusterDeploy at least 2 HSMs across AZs for high availability. Initialize the cluster and set crypto officer credentials.
- Create Custom Key Store in KMSLink KMS to your CloudHSM cluster. KMS authenticates as a crypto user (kmsuser) on the HSMs.
- Create CMKs in Custom Key StoreKeys created here have
Origin: AWS_CLOUDHSM. Key material lives exclusively in your HSM cluster. - Use like any other CMKAll KMS APIs work the same. AWS services integrate seamlessly. The difference is where key material lives.
XKS (launched 2022) lets you store and use key material in an HSM entirely outside of AWS β in your own data center or another cloud. KMS proxies requests to your external key manager.
External key stores have higher latency, lower throughput, and introduce a dependency on external infrastructure. If your key manager goes offline, AWS services using those keys will fail. This is by design β it gives you the "kill switch."
You can import your own symmetric key material into a KMS key instead of letting KMS generate it. This gives you control over key generation but adds significant operational burden.
- Create CMK with no key materialSpecify
Origin: EXTERNAL. KMS creates the key metadata and policy but leaves the key material empty. - Download wrapping key & import tokenKMS provides an RSA public key (wrapping key) and an import token. These expire in 24 hours.
- Encrypt your key materialWrap your 256-bit symmetric key with the RSA wrapping key using RSAES_OAEP_SHA_256.
- Import into KMSUpload the wrapped key + import token. Optionally set an expiration date (key auto-deletes material when expired).
BYOK Use Cases
- Prove key generated in specific HSM
- Set key expiration (material auto-deletes)
- Comply with "key generated on-premises" rules
- Same key material across multiple regions
- Maintain key escrow outside AWS
BYOK Limitations
- No automatic key rotation
- Cannot use with Custom Key Store
- You're responsible for key material backup
- Delete material β must re-import (if you still have it)
- Only symmetric + HMAC keys supported
Multi-Region keys share the same key material across multiple AWS regions. They look like independent keys but can decrypt each other's ciphertext.
Multi-Region keys have a key ID starting with mrk- (e.g., mrk-1234abcd...). This prefix is how you identify them. Standard keys start with a random UUID.
What Replicates
- Key material (cryptographic bytes)
- Key ID (same mrk- ID in all regions)
- Automatic rotation setting
- Key spec and key usage
What Does NOT Replicate
- Key policy (independent per region)
- Tags (set separately per region)
- Aliases (create in each region)
- Grants (region-specific)
Max ~13 regions per MRK (soft limit). Deleting primary does NOT delete replicas (they become independent). Not supported for asymmetric keys or imported key material. Cannot change key material after initial replication.
| Key Type | Rotation | Period | Behavior |
|---|---|---|---|
| AWS Managed | Automatic (mandatory) | Every year (365 days) | Cannot disable or change period |
| Customer Managed (KMS material) | Optional (configurable) | 90β2560 days | You choose period, can disable |
| Customer Managed (imported) | Manual only | β | Must create new key + re-import |
| Asymmetric keys | Manual only | β | Create new key + distribute public key |
| HMAC keys | Manual only | β | Create new key + update applications |
| Custom Key Store | Manual only | β | Rotation not supported automatically |
When a key rotates, KMS generates new backing material but keeps the same Key ID and ARN. New encryptions use the new material. Old ciphertext is still decryptable because KMS retains all previous backing materials indefinitely. Your code never changes.
IAM Roles Anywhere lets on-premises workloads obtain temporary AWS credentials using X.509 certificates. Combined with KMS, this enables:
Pattern: Hybrid Encryption
- On-prem server has X.509 cert from private CA
- Authenticates via IAM Roles Anywhere
- Gets temporary AWS credentials
- Calls
kms:Decrypt/kms:GenerateDataKey - Encrypts/decrypts data locally
Benefits
- No long-term credentials stored on-prem
- Full CloudTrail audit of on-prem KMS usage
- Same key policies control on-prem + cloud
- Rotate certificates (not static keys)
- Revoke access by revoking cert trust
Nitro Enclaves create isolated virtual machines with no persistent storage, no network, and no operator access. KMS can be configured to only release keys to a specific enclave:
kms:RecipientAttestation:ImageSha384 condition to restrict decrypt to a specific enclave image.- "FIPS 140-2 Level 3" β Custom Key Store (CloudHSM). Standard KMS is Level 2.
- "Keys must not reside in AWS" β External Key Store (XKS).
- "Kill switch to revoke all AWS access" β XKS β disconnect the proxy.
- "Same key material in multiple regions" β Multi-Region keys (mrk- prefix).
- "Key rotation for imported keys" β Manual only. Create new key, import new material, update alias.
- "DR for encrypted data" β Multi-Region keys OR replicate + re-encrypt in target region.
- "On-premises workload needs KMS" β IAM Roles Anywhere + KMS API calls.
- "Process sensitive data, even admin can't see" β Nitro Enclaves with KMS attestation condition.
- "Key has expiration date" β Imported key material with expiration set.
- Custom Key Store: CloudHSM-backed. FIPS 140-2 Level 3. Single-tenant. ~$1.50/hr per HSM. You manage availability.
- External Key Store (XKS): Key material outside AWS entirely. Kill switch capability. Highest latency. Data sovereignty.
- BYOK (Imported): Generate key on-prem β wrap β upload. No auto-rotation. Optional expiration. You maintain backup.
- Multi-Region keys: Same key material replicated across regions. mrk- prefix. Encrypt in one region, decrypt in another.
- Auto-Rotation: New backing material, same Key ID. Old ciphertext still decryptable. 90β2560 day configurable period.
- IAM Roles Anywhere: On-prem β X.509 cert β temporary AWS creds β KMS access. No long-term keys.
- Nitro Enclaves: KMS releases keys only to attested enclave images. Even instance admin cannot see plaintext.
Standard KMS β Custom Key Store β External Key Store is a spectrum from most convenient to most control. Multi-Region keys solve DR/global apps. BYOK gives generation control. Choose based on compliance requirements β 99% of workloads should use standard KMS.
This final chapter ties everything together with real-world architecture patterns that combine KMS concepts into production-ready solutions. These are the patterns that appear in architecture reviews, certification exams, and enterprise deployments.
Enterprise organizations with multiple AWS accounts need a centralized encryption strategy. The recommended approach:
Centralized Key Account
- Dedicated "Security/Keys" account
- All CMKs created and managed here
- Key administrators in this account only
- Cross-account key policies grant usage
- Centralized audit via CloudTrail
Workload Accounts
- IAM roles with kms:Encrypt/Decrypt
- Reference keys by alias ARN or key ARN
- Cannot modify key policies
- Cannot delete keys
- Separation: data owners β key owners
Centralized management means one team controls encryption policy. Even if a workload account is compromised, the attacker cannot modify key policies or delete keys. Revoking access = update one key policy statement.
A data lake encryption pattern that uses different CMKs per data classification:
| Classification | S3 Prefix | KMS Key | Access |
|---|---|---|---|
| Public | s3://lake/public/ | SSE-S3 (no KMS) | Anyone with bucket access |
| Internal | s3://lake/internal/ | CMK: internal-data-key | All data team roles |
| Confidential | s3://lake/confidential/ | CMK: confidential-key | Restricted analysts only |
| Restricted/PII | s3://lake/restricted/ | CMK: pii-key | DPO + specific approved roles |
Key insight: Even if someone has s3:GetObject on the entire bucket, they cannot read restricted data without kms:Decrypt permission on the PII key. KMS becomes your secondary access control layer.
- Create Multi-Region KMS keyPrimary in us-east-1, replica in us-west-2. Same key material in both regions.
- Encrypt data in primary regionS3 objects, EBS snapshots, RDS automated backups β all encrypted with the multi-region key.
- Replicate to DR regionS3 Cross-Region Replication, EBS snapshot copy, RDS cross-region read replica.
- Failover β decrypt immediatelyData is decryptable immediately in DR region using the local replica key. No re-encryption needed. No cross-region KMS calls.
- Promote replica if primary failsIf primary region is permanently lost, promote the replica to primary. Full control maintained in DR region.
Defense-in-depth using KMS condition keys to build a zero-trust encryption layer:
Layer Stack
- Network: VPC endpoint policy restricts KMS access to specific VPC
- Identity: IAM policy with kms: actions + resource ARN
- Resource: Key policy with kms:ViaService condition
- Context: Encryption context must match expected values
- Time: Grants with expiration for temporary access
Result
- Compromise of IAM alone β insufficient
- Compromise of S3 alone β can't decrypt
- Must satisfy ALL layers simultaneously
- Full audit trail in CloudTrail
- Instant revocation at any layer
- Store secrets in Secrets Manager (CMK-encrypted)Database passwords, API keys, certificates stored encrypted with a dedicated CI/CD CMK.
- Pipeline role gets temporary access via grantCodePipeline/CodeBuild assume role with
kms:Decryptpermission. Grant auto-retires after pipeline completes. - Encryption context ties secret to pipelineKey policy requires encryption context:
{"pipeline": "prod-deploy", "stage": "build"}. Wrong context = denied. - CloudTrail captures every accessFull audit: who accessed which secret, when, from which pipeline. Alert on unexpected access patterns.
- AWS service encrypts after receiving data
- Data in transit is plaintext (HTTPS protected)
- AWS handles key management transparently
- Simpler implementation
- Sufficient for most use cases
- You encrypt before sending to AWS
- Data encrypted end-to-end
- AWS never sees plaintext data
- You control encryption logic
- Required for highest security / compliance
The AWS Encryption SDK implements envelope encryption client-side with best practices built in: authenticated encryption, data key caching, multiple master key support, and message format that stores encrypted data keys alongside ciphertext.
AWS Config Rules for KMS
cmk-backing-key-rotation-enabledkms-cmk-not-scheduled-for-deletions3-bucket-server-side-encryption-enabledencrypted-volumesrds-storage-encrypted
SCP Guardrails (Organizations)
- Deny
kms:DisableKeyfor non-security roles - Deny
kms:ScheduleKeyDeletionbroadly - Require CMK for all S3/EBS/RDS encryption
- Deny
kms:PutKeyPolicywithout approval tag - Enforce encryption context on API operations
| Scenario | Pattern | Key Chapter |
|---|---|---|
| Encrypt large files | Envelope encryption + GenerateDataKey | Ch04 |
| S3 encryption at scale | SSE-KMS + Bucket Keys enabled | Ch06 |
| Cross-account data sharing | Key policy + IAM policy (dual auth) | Ch05 |
| Global application DR | Multi-Region keys | Ch07 |
| External client encrypts | Asymmetric RSA key (public key distributed) | Ch03 |
| CI/CD secrets | Secrets Manager + CMK + grants | Ch08 |
| Regulatory single-tenant HSM | Custom Key Store (CloudHSM) | Ch07 |
| Data sovereignty | External Key Store (XKS) | Ch07 |
| Prevent accidental deletion | SCP deny + separate admin role | Ch05 |
| Audit all key usage | CloudTrail + CloudWatch alarms | Ch06 |
- "Centralized key management" β Dedicated security account + cross-account key policies.
- "Different encryption per data classification" β Multiple CMKs, restrict decrypt by role per classification.
- "DR for encrypted data without re-encryption" β Multi-Region keys.
- "Ensure all resources are encrypted" β AWS Config rules + SCP deny unencrypted resource creation.
- "Client-side encryption before upload" β AWS Encryption SDK with KMS master key provider.
- "Zero-trust data access" β Layer: VPC endpoint + IAM + Key Policy + Encryption Context + Grants.
- "Prevent any admin from accessing data" β Nitro Enclaves with KMS attestation conditions.
- Multi-Account: Central security account owns keys. Workload accounts get scoped usage. One revocation point.
- Data Lake: Different CMKs per classification. KMS = secondary access control beyond S3 policies.
- Cross-Region DR: Multi-Region keys β data decryptable immediately after failover.
- Zero Trust: 5 layers (network + identity + key policy + context + grants). Must pass ALL.
- CI/CD Secrets: Secrets Manager + dedicated CMK + encryption context binding + ephemeral grants.
- Client-Side: AWS Encryption SDK. Encrypt before AWS sees data. For highest compliance.
- Governance: AWS Config rules + SCPs enforce encryption standards organization-wide.
KMS is not just a service β it's the foundation of your entire AWS security architecture. Centralize key management, use multiple CMKs for blast radius reduction, layer defenses, and treat KMS as the control plane for data access. Every architecture decision about "who can access what data" should have a KMS component.
| Term | Definition |
|---|---|
| CMK | Customer Master Key β the logical KMS key resource you create and manage |
| Key Material | The actual cryptographic bytes used for encryption/decryption |
| Backing Key | The underlying key material (multiple exist over time with rotation) |
| Data Key | A key generated by KMS for local envelope encryption (not stored in KMS) |
| Envelope Encryption | Pattern: encrypt data key with CMK, then use data key to encrypt data locally |
| Encryption Context | Key-value pairs cryptographically bound to ciphertext; required for decryption |
| Key Policy | Resource-based JSON policy attached to each KMS key (mandatory, max 32 KB) |
| Grant | Temporary, programmatic permission delegation for KMS key access |
| Alias | Friendly name pointer to a CMK (e.g., alias/prod-key); updateable without code changes |
| Custom Key Store | KMS key backed by your own dedicated CloudHSM cluster |
| XKS | External Key Store β key material stored outside AWS entirely (via XKS Proxy) |
| BYOK | Bring Your Own Key β import externally-generated key material into KMS |
| Multi-Region Key | Key replicated across regions with same material (mrk- prefix) |
| FIPS 140-2 | US government security standard for cryptographic modules (Level 2 = KMS, Level 3 = CloudHSM) |
| HSM | Hardware Security Module β tamper-resistant hardware for key storage and operations |
| S3 Bucket Key | Intermediate cached key that reduces KMS API calls by 99% for S3 SSE-KMS |
| Service | Relationship to KMS | When to Use |
|---|---|---|
| AWS CloudHSM | Alternative (dedicated HSM for KMS custom key store) | Regulatory requiring single-tenant HSM / FIPS Level 3 |
| AWS Certificate Manager (ACM) | Different purpose (TLS certificates, not data-at-rest) | HTTPS termination at ALB, CloudFront, API Gateway |
| AWS Secrets Manager | Uses KMS for envelope encryption of secrets | Store and rotate database passwords, API keys |
| SSM Parameter Store | Uses KMS for SecureString encryption | Application configuration with optional encryption |
| AWS Nitro Enclaves | Uses KMS with attestation conditions | Process sensitive data with hardware-level isolation |
| AWS Encryption SDK | Client-side library that wraps KMS for envelope encryption | Encrypt before sending to AWS; multi-key, caching built in |
| ACM Private CA | Different purpose (internal X.509 certificates) | Internal mTLS, code signing, IoT device identity |
AWS KMS Developer Guide β the authoritative reference for all APIs, quotas, and service integrations. AWS Encryption SDK docs β for client-side envelope encryption implementation. AWS Security Blog β for architecture patterns and best practices.