/AWS KMS & Encryption
Concept
Hard

AWS KMS & Encryption

15 min read·KMSEncryptionSecurityDVA-C02

A comprehensive deep dive into AWS Key Management Service — key types, envelope encryption, key policies, grants, rotation, multi-region keys, service integrations, CloudHSM, and encryption patterns for the DVA-C02 exam.


What is AWS KMS?

AWS Key Management Service (KMS) is a managed encryption service that creates and controls cryptographic keys used to encrypt data across AWS services and your own applications. KMS runs on FIPS 140-2 validated Hardware Security Modules (HSMs) — the physical hardware that stores and never exports key material.

Core mental model: KMS never gives you the raw key — it performs cryptographic operations on your behalf inside its HSMs. You call KMS APIs; KMS does the math and returns ciphertext or plaintext. Your key material never leaves AWS KMS unencrypted.


Key Types

Key TypeAliasCostRotationControlCross-Account
AWS Owned KeysNone (internal)FreeAutomaticNoneNo
AWS Managed Keysaws/s3, aws/rds, etc.FreeAutomatic (annual)View onlyNo
Customer Managed Keys (CMK)Custom alias$1/monthOptional (annual or on-demand)FullYes
External Key Material (BYOK)Custom alias$1/monthManual onlyFullYes
CloudHSM-backed KeysCustom alias$1/month + HSM costManualFullYes

Key rule for the exam: You can only control key policy, grants, and rotation for Customer Managed Keys. AWS Managed and Owned keys are not directly manageable.


Key Material Origin

When you create a CMK, you choose where the key material comes from:

Rendering diagram…
OriginKey generated byDeletionUse case
AWS_KMSKMS HSMSchedule deletion (7–30 days)Default — most use cases
EXTERNALYou (imported)Immediate delete allowedCompliance: bring own key material
AWS_CloudHSMYour CloudHSM clusterSchedule deletionDedicated hardware requirement

KMS API Operations

APIInput Size LimitReturnsUse case
Encrypt4 KBCiphertext blobEncrypt small data (passwords, tokens)
Decrypt6 KB ciphertextPlaintextDecrypt data encrypted by KMS
ReEncrypt6 KB ciphertextNew ciphertextRotate encryption to new key without exposing plaintext
GenerateDataKeyN/APlaintext DEK + encrypted DEKEnvelope encryption of large data
GenerateDataKeyWithoutPlaintextN/AEncrypted DEK onlyGenerate and store DEK for later use
GenerateRandomUp to 1024 bytesRandom bytesCryptographically secure random data
DescribeKeyN/AKey metadataInspect key state and metadata
ListKeys / ListAliasesN/AListEnumerate keys

4 KB limit is critical for the exam. Direct Encrypt only handles up to 4 KB. For anything larger, you must use envelope encryption with GenerateDataKey.


Envelope Encryption (Deep Dive)

Envelope encryption solves the 4 KB limit by using KMS to protect a Data Encryption Key (DEK), then using the DEK locally to encrypt arbitrarily large data.

Rendering diagram…

Envelope Encryption in Code

javascript
1import { KMSClient, GenerateDataKeyCommand, DecryptCommand } from '@aws-sdk/client-kms';
2import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
3
4const kms = new KMSClient({ region: 'us-east-1' });
5const KEY_ID = 'arn:aws:kms:us-east-1:123456789012:key/mrk-abc123';
6
7// ─── ENCRYPT ─────────────────────────────────────────────────────────────────
8async function encryptLargeData(plaintext) {
9  // 1. Ask KMS for a data key (symmetric AES-256)
10  const { Plaintext: dek, CiphertextBlob: encryptedDek } = await kms.send(
11    new GenerateDataKeyCommand({ KeyId: KEY_ID, KeySpec: 'AES_256' })
12  );
13
14  // 2. Encrypt the data locally with the plaintext DEK
15  const iv = randomBytes(12);                            // 96-bit IV for GCM
16  const cipher = createCipheriv('aes-256-gcm', dek, iv);
17  const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
18  const authTag = cipher.getAuthTag();
19
20  // 3. Immediately discard the plaintext DEK
21  dek.fill(0);
22
23  // 4. Store: encrypted payload + encrypted DEK + IV + authTag
24  return {
25    encryptedData: encrypted.toString('base64'),
26    encryptedDek: Buffer.from(encryptedDek).toString('base64'),
27    iv: iv.toString('base64'),
28    authTag: authTag.toString('base64'),
29  };
30}
31
32// ─── DECRYPT ─────────────────────────────────────────────────────────────────
33async function decryptLargeData({ encryptedData, encryptedDek, iv, authTag }) {
34  // 1. Ask KMS to decrypt the encrypted DEK
35  const { Plaintext: dek } = await kms.send(
36    new DecryptCommand({
37      CiphertextBlob: Buffer.from(encryptedDek, 'base64'),
38      KeyId: KEY_ID,        // optional but recommended for extra safety
39    })
40  );
41
42  // 2. Decrypt the data locally
43  const decipher = createDecipheriv(
44    'aes-256-gcm',
45    dek,
46    Buffer.from(iv, 'base64')
47  );
48  decipher.setAuthTag(Buffer.from(authTag, 'base64'));
49  const decrypted = Buffer.concat([
50    decipher.update(Buffer.from(encryptedData, 'base64')),
51    decipher.final(),
52  ]);
53
54  dek.fill(0);  // zero out plaintext DEK
55  return decrypted.toString();
56}

Data Key Caching

Calling GenerateDataKey for every operation is expensive (cost + latency). The AWS Encryption SDK supports data key caching to reuse a DEK across multiple operations.

javascript
1import {
2  KmsKeyringNode,
3  buildClient,
4  CommitmentPolicy,
5  LocalCryptographicMaterialsCache,
6  CachingMaterialsManager,
7} from '@aws-crypto/client-node';
8
9const { encrypt, decrypt } = buildClient(CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT);
10
11const keyring = new KmsKeyringNode({ generatorKeyId: KEY_ID });
12
13// Cache: reuse DEK for up to 60 seconds or 100 messages, whichever comes first
14const cache = new LocalCryptographicMaterialsCache(100);
15const cachingCMM = new CachingMaterialsManager({
16  backingMaterialsManager: keyring,
17  cache,
18  maxAge: 60_000,          // 60 seconds
19  maxMessagesEncrypted: 100,
20});
21
22const { result } = await encrypt(cachingCMM, 'Hello, cached world!');
Cache limitMeaning
maxAgeDEK expires after this many milliseconds
maxMessagesEncryptedDEK is retired after encrypting N messages
maxBytesEncryptedDEK is retired after encrypting N bytes

KMS Key Policies

Key policies are resource-based policies attached to the KMS key. Unlike most AWS resources, IAM policies alone are not sufficient — the key policy must explicitly allow access.

json
1{
2  "Version": "2012-10-17",
3  "Statement": [
4    {
5      "Sid": "Enable IAM policies",
6      "Effect": "Allow",
7      "Principal": { "AWS": "arn:aws:iam::123456789012:root" },
8      "Action": "kms:*",
9      "Resource": "*"
10    },
11    {
12      "Sid": "Allow app role to use the key",
13      "Effect": "Allow",
14      "Principal": { "AWS": "arn:aws:iam::123456789012:role/AppRole" },
15      "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey"],
16      "Resource": "*"
17    },
18    {
19      "Sid": "Allow key admin",
20      "Effect": "Allow",
21      "Principal": { "AWS": "arn:aws:iam::123456789012:role/KeyAdminRole" },
22      "Action": [
23        "kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*",
24        "kms:Put*", "kms:Update*", "kms:Revoke*", "kms:Disable*",
25        "kms:Get*", "kms:Delete*", "kms:TagResource", "kms:UntagResource",
26        "kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion"
27      ],
28      "Resource": "*"
29    }
30  ]
31}

Critical rule: The first statement (Enable IAM policies) delegates control to IAM in the account. Without this, no IAM policy in the account can grant KMS access for this key. If you accidentally remove it, you must contact AWS Support to regain access.

Cross-Account Key Access

Rendering diagram…

Both the key policy in Account A (must allow Account B) AND an IAM policy in Account B (must explicitly allow the KMS action) are required. Neither alone is sufficient.


KMS Grants

Grants are an alternative to key policies for programmatic, temporary, delegated access. Useful when a service needs to use a key on behalf of a user without modifying the key policy.

bash
1# Create a grant — allow a Lambda execution role to decrypt
2aws kms create-grant   --key-id mrk-abc123   --grantee-principal arn:aws:iam::123456789012:role/LambdaRole   --operations Decrypt GenerateDataKey   --name "lambda-access-grant"
3
4# List grants on a key
5aws kms list-grants --key-id mrk-abc123
6
7# Retire a grant (by the grantee)
8aws kms retire-grant --grant-token <token>
9
10# Revoke a grant (by the key admin)
11aws kms revoke-grant --key-id mrk-abc123 --grant-id <id>
Key PolicyGrant
Who modifiesKey adminAny principal with kms:CreateGrant
PersistencePermanent until changedRevocable / retirable
Cross-accountYesYes
Use caseStatic accessService delegation, temporary access

Key Rotation

Key TypeRotation TypeFrequencyOld key material
AWS ManagedAutomaticEvery yearRetained to decrypt old ciphertext
CMK (AWS_KMS origin)Automatic (if enabled)Every yearRetained
CMK (AWS_KMS origin)On-demandAnytimeRetained
External (BYOK)ManualYou decideYou manage old versions
CloudHSM-backedManualYou decideYou manage
bash
1# Enable automatic annual rotation for a CMK
2aws kms enable-key-rotation --key-id mrk-abc123
3
4# Rotate immediately (on-demand) — no downtime, old versions retained
5aws kms rotate-key-on-demand --key-id mrk-abc123
6
7# Check rotation status
8aws kms get-key-rotation-status --key-id mrk-abc123

Key insight: Rotation creates a new backing key (new cryptographic material) but the Key ARN stays the same. Ciphertext encrypted with old backing keys is automatically decrypted using the retained old key material. No re-encryption of existing data needed.


Multi-Region Keys (MRK)

Multi-Region Keys are interoperable KMS keys that can be replicated across AWS regions. Ciphertext encrypted in one region can be decrypted in another without re-encryption via KMS.

Rendering diagram…
bash
1# Create a primary MRK
2aws kms create-key   --multi-region   --description "Primary MRK for global app"   --region us-east-1
3
4# Replicate to another region
5aws kms replicate-key   --key-id arn:aws:kms:us-east-1:123456789012:key/mrk-abc123   --replica-region eu-west-1

When to use MRKs:

  • Disaster recovery: decrypt data in a backup region without additional KMS calls
  • Global applications: low-latency encryption/decryption in the user's region
  • Active-active multi-region architectures with DynamoDB Global Tables

S3 Encryption Options

MethodKey managed byKMS API call per objectHeader
SSE-S3S3 (AES-256)Nox-amz-server-side-encryption: AES256
SSE-KMSKMS CMKYes (GenerateDataKey)x-amz-server-side-encryption: aws:kms
DSSE-KMSKMS CMKYes (dual-layer)x-amz-server-side-encryption: aws:kms:dsse
SSE-CYou (per request)Nox-amz-server-side-encryption-customer-key
Client-sideYou (before upload)OptionalNone
bash
1# Upload object with SSE-KMS
2aws s3 cp secret.txt s3://my-bucket/secret.txt   --sse aws:kms   --sse-kms-key-id alias/my-key
3
4# Set default bucket encryption to SSE-KMS
5aws s3api put-bucket-encryption   --bucket my-bucket   --server-side-encryption-configuration '{
6    "Rules": [{
7      "ApplyServerSideEncryptionByDefault": {
8        "SSEAlgorithm": "aws:kms",
9        "KMSMasterKeyID": "alias/my-key"
10      },
11      "BucketKeyEnabled": true
12    }]
13  }'

S3 Bucket Key: Reduces KMS API calls by generating a short-lived bucket-level DEK. A single GenerateDataKey call serves thousands of S3 objects instead of one call per object. Reduces KMS costs by ~99% for high-volume buckets.


KMS with AWS Services

ServiceHow KMS integratesKey option
S3SSE-KMS per object or bucket defaultCMK or AWS Managed (aws/s3)
EBSVolume encryption at restCMK or AWS Managed (aws/ebs)
RDSEncryption at rest on instance creationCMK or AWS Managed (aws/rds)
LambdaEncrypt environment variablesCMK
Secrets ManagerEncrypt secret valueCMK (default: aws/secretsmanager)
CloudTrailEncrypt log files in S3CMK
SSM Parameter StoreSecureString parametersCMK or AWS Managed (aws/ssm)
SNSEncrypt messages at restCMK
SQSEncrypt messages at rest (SSE-SQS or SSE-KMS)CMK or AWS Managed (aws/sqs)
javascript
1// Lambda environment variable encryption with CMK
2import { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';
3
4const kms = new KMSClient({});
5
6// Lambda auto-decrypts env vars with the key at startup.
7// For additional client-side decryption (when using your own CMK):
8async function getDecryptedSecret() {
9  const { Plaintext } = await kms.send(new DecryptCommand({
10    CiphertextBlob: Buffer.from(process.env.ENCRYPTED_API_KEY, 'base64'),
11  }));
12  return Buffer.from(Plaintext).toString('utf-8');
13}

Asymmetric Keys

KMS supports asymmetric key pairs for signing/verification and public-key encryption.

Key SpecAlgorithmUse case
RSA_2048 / RSA_4096RSA-OAEPAsymmetric encryption
ECC_NIST_P256 / ECC_NIST_P384ECDSADigital signing
RSA_2048 (signing)RSASSA-PSS / PKCS1v15Document/JWT signing
SM2SM2China regions only
javascript
1import { KMSClient, SignCommand, VerifyCommand } from '@aws-sdk/client-kms';
2import { createHash } from 'crypto';
3
4const kms = new KMSClient({});
5const SIGNING_KEY_ID = 'alias/my-signing-key';
6
7// Sign a message
8async function signPayload(message) {
9  const messageHash = createHash('sha256').update(message).digest();
10
11  const { Signature } = await kms.send(new SignCommand({
12    KeyId: SIGNING_KEY_ID,
13    Message: messageHash,
14    MessageType: 'DIGEST',
15    SigningAlgorithm: 'ECDSA_SHA_256',
16  }));
17  return Buffer.from(Signature).toString('base64');
18}
19
20// Verify signature (can use public key locally — no KMS call needed)
21async function verifySignature(message, signature) {
22  const messageHash = createHash('sha256').update(message).digest();
23
24  const { SignatureValid } = await kms.send(new VerifyCommand({
25    KeyId: SIGNING_KEY_ID,
26    Message: messageHash,
27    MessageType: 'DIGEST',
28    Signature: Buffer.from(signature, 'base64'),
29    SigningAlgorithm: 'ECDSA_SHA_256',
30  }));
31  return SignatureValid;
32}

The public key can be downloaded from KMS (GetPublicKey) and distributed freely. Signature verification can happen locally without any KMS API call — only signing requires KMS.


Key States

Rendering diagram…
StateEncryptDecryptKey policy changes
Enabled
Disabled
Pending Deletion
Pending Import

Scheduled deletion window: 7 days minimum, 30 days maximum. During this window you can cancel deletion. After the window passes, the key is permanently and irrecoverably deleted.


AWS CloudHSM

CloudHSM provides dedicated, single-tenant Hardware Security Modules in your VPC. Unlike KMS (shared, multi-tenant HSMs), CloudHSM gives you exclusive access to the hardware.

Rendering diagram…
KMSCloudHSM
HardwareShared (multi-tenant)Dedicated (single-tenant)
ComplianceFIPS 140-2 Level 2FIPS 140-2 Level 3
Key managementAWS shares responsibilityYou have full control
CostPer-requestPer HSM per hour (~$1.60/hr)
IntegrationNative AWS service integrationManual SDK integration (PKCS#11, JCE)
High availabilityBuilt-inYou must create a cluster (min 2 HSMs)
Root of Trust for KMSOptionalNot applicable

When to use CloudHSM: Regulatory requirement for dedicated hardware, FIPS 140-2 Level 3, custom cryptographic operations, or when you need to be the sole owner of the HSM.


Key Policy + Grant + IAM Evaluation Logic

Rendering diagram…

Rule: For KMS, both the key policy AND (IAM policy OR grant) must allow. An explicit deny anywhere always wins.


DVA-C02 Quick Reference

TopicKey Fact
Direct KMS Encrypt limit4 KB maximum
Envelope encryption whyKMS 4 KB limit → use DEK for large data
GenerateDataKey returnsPlaintext DEK + Encrypted DEK
GenerateDataKeyWithoutPlaintextReturns encrypted DEK only (no plaintext)
CMK cost$1/month per key + $0.03 per 10,000 API calls
AWS Managed Key costFree
Automatic rotation frequencyAnnually (CMK optional, AWS Managed automatic)
Rotation effect on ARNARN unchanged — new backing key created
Key policy root statementRequired — enables IAM delegation; without it, no IAM policy works
Cross-account access requiresKey policy in owner account AND IAM policy in user account
Grants vs key policiesGrants are programmatic, revocable — policies are static
S3 Bucket Key benefitReduces KMS API calls by up to 99%
SSE-KMS API callGenerateDataKey per S3 object (without Bucket Key)
SSE-S3 vs SSE-KMSSSE-S3: no audit trail; SSE-KMS: CloudTrail logs every decryption
Multi-Region Key prefixmrk- prefix on Key ID
MRK benefitEncrypt in one region, decrypt in another without re-encryption
Key deletion minimum window7 days (max 30 days)
Key permanently deletedCannot be recovered — all encrypted data permanently inaccessible
CloudHSM FIPS levelFIPS 140-2 Level 3 (vs KMS Level 2)
CloudHSM vs KMSCloudHSM: dedicated hardware, you manage; KMS: managed service
KMS + CloudTrailEvery KMS API call logged — who used what key, when
Asymmetric: verify without KMSDownload public key with GetPublicKey — verify locally

Practice Questions5

medium

Q1. A developer needs to encrypt a 5 MB file using AWS KMS. The KMS Encrypt API rejects the request. What is the correct approach for encrypting large data?


Select one answer before revealing.

hard

Q2. A company requires that all KMS key operations be logged and that only specific IAM roles can perform kms:Decrypt. The developer needs to ensure no other principal can use the key, even AWS account root. Which KMS feature enforces this?


Select one answer before revealing.

hard

Q3. A Lambda function calls kms:GenerateDataKey on every invocation to encrypt user data. This is causing KMS API throttling (429 errors). How should the developer reduce KMS API calls without sacrificing security?


Select one answer before revealing.

easy

Q4. A developer stores a Lambda function's database password in an environment variable encrypted with KMS. The function needs to decrypt the password at startup. Which KMS API should be called?


Select one answer before revealing.

hard

Q5. A company has a KMS key used to encrypt S3 objects. They want to allow a Lambda in account B to decrypt these objects, but the KMS key is in account A. What configuration is required?


Select one answer before revealing.