examhub .cc 用最有效率的方法,考取最有價值的認證
Vol. I
本篇導覽 約 32 分鐘

AWS KMS 與信封加密

6,400 字 · 約 32 分鐘閱讀

AWS KMS encryption is the developer-facing set of AWS Key Management Service (AWS KMS) APIs and SDK patterns that let application code encrypt, decrypt, sign, verify, and rotate cryptographic material without ever handling raw key bytes. For a DVA-C02 candidate, AWS KMS encryption is not a box you check on a storage console — it is code you write: kms:Encrypt for tiny secrets under 4 KB, kms:GenerateDataKey for the envelope encryption pattern that protects multi-gigabyte payloads, kms:ReEncrypt for rotating keys without decrypting ciphertext in your own process, kms:Sign and kms:Verify for digital signatures, and encryption context strings used as Additional Authenticated Data (AAD) on every call. This guide walks through every AWS KMS encryption API a developer touches, the SDK parameters that toggle SSE-KMS on PutObject, the Lambda environment variable encryption helper, client-side encryption with the AWS Encryption SDK and the Amazon DynamoDB Encryption Client, KMS grants for delegated temporary access, multi-Region keys for cross-Region code paths, and the shared-throttling quotas that will bite a high-throughput service if you do not plan for them.

On the DVA-C02 exam, Domain 2 ("Development with AWS Services") and Domain 3 ("Deployment") both expect fluent AWS KMS encryption decisions inside SDK code. Expect scenarios that ask "which AWS KMS API call protects a 20 MB file efficiently?" (GenerateDataKey, not Encrypt), "how do I bind ciphertext to a tenant identifier?" (encryption context as AAD), "how do I rotate ciphertext to a new AWS KMS key without exposing plaintext?" (ReEncrypt), "how does a Lambda function decrypt its own environment variable?" (KMS helper with AWS_LAMBDA_FUNCTION_NAME encryption context), and "why is my service suddenly throttled at 10,000 req/s?" (shared AWS KMS request quotas per Region). Answer those with code-level confidence and AWS KMS encryption becomes a DVA-C02 strength rather than a time sink.

What is AWS KMS Encryption for Developers?

AWS KMS encryption for developers is the programmatic surface of AWS KMS — the APIs, SDK helpers, and client-side libraries that a developer invokes from Amazon EC2, AWS Lambda, Amazon ECS, AWS Fargate, AWS App Runner, or anywhere the AWS SDK runs. AWS KMS itself holds the key material in hardware security modules and never releases the AWS KMS key (formerly customer master key, CMK) to your code; instead, it accepts small requests, performs the cryptographic operation inside its own boundary, and returns either ciphertext, plaintext, a data key, a signature, or a verification result.

A developer interacts with AWS KMS encryption through six recurring patterns:

  1. Direct kms:Encrypt / kms:Decrypt for tiny payloads up to 4,096 bytes (4 KB) — typical for secrets, tokens, and small configuration blobs.
  2. Envelope encryption via kms:GenerateDataKey — the pattern for anything larger than 4 KB, which is almost everything in production.
  3. kms:ReEncrypt — rotating ciphertext from one AWS KMS key to another without the plaintext ever leaving AWS KMS.
  4. Asymmetric operations (kms:Sign, kms:Verify, kms:GetPublicKey) — for digital signatures, document signing, and JWT validation.
  5. Server-side encryption integrations (Amazon S3 SSE-KMS, Amazon DynamoDB, Amazon SQS, Amazon SNS, AWS Lambda environment variables) driven by SDK parameters rather than by direct AWS KMS calls.
  6. Client-side encryption with the AWS Encryption SDK, the Amazon S3 Encryption Client, or the Amazon DynamoDB Encryption Client, which wrap AWS KMS calls behind high-level encrypt/decrypt methods.
  • AWS KMS key: the logical key object inside AWS KMS. Key material never leaves AWS KMS. Also known historically as the customer master key (CMK).
  • Data key: a 128-bit or 256-bit symmetric key that AWS KMS generates on demand for bulk data encryption. Returned both as plaintext and as ciphertext from GenerateDataKey.
  • Envelope encryption: encrypting customer data with a data key, and then encrypting the data key with an AWS KMS key. The default pattern for anything over 4 KB.
  • Encryption context: a non-secret key/value map passed on every AWS KMS encrypt or decrypt call. Used as Additional Authenticated Data (AAD) and must match exactly on decrypt.
  • Grant: a temporary, narrowly scoped delegation of AWS KMS permissions. Created programmatically by services or your own code.
  • Multi-Region key: a set of AWS KMS keys in multiple AWS Regions that share the same key ID and key material, used for cross-Region code paths.
  • AWS KMS request quota: per-Region, per-account, per-key-type limit on AWS KMS API requests per second. Shared across all AWS services in the account.
  • Reference: https://docs.aws.amazon.com/kms/latest/developerguide/overview.html

Why AWS KMS Encryption Matters for DVA-C02

AWS KMS encryption shows up across three DVA-C02 domains. Domain 2 ("Development with AWS Services") tests whether you can wire AWS KMS calls into Amazon S3, Amazon DynamoDB, AWS Lambda, and Amazon SQS correctly inside SDK code. Domain 3 ("Deployment") asks about encrypting deployment artifacts, encrypting AWS Lambda environment variables, and using AWS KMS keys referenced from AWS CloudFormation templates. Domain 4 ("Troubleshooting and Optimization") asks about AWS KMS throttling, InvalidCiphertextException on encryption-context mismatch, and CloudTrail debugging. Get AWS KMS encryption right and you have picked up easy points in three out of four exam domains.

白話文解釋 AWS KMS Encryption for Developers

Four distinct, developer-flavored analogies that together cover every AWS KMS encryption construct on DVA-C02.

Analogy 1: The Workshop Master Tool Chest (Envelope Encryption in Code)

Picture a workshop with a master tool chest bolted to the floor — it is heavy, it never leaves the workshop, and only the foreman has the combination. That master tool chest is the AWS KMS key. For each job, a worker (your application code) asks the foreman for a fresh single-use screwdriver (the data key). The foreman takes a new screwdriver out of the chest, hands the worker two copies: one ready to use (the plaintext data key) and one sealed inside a labeled lockbox that only the master chest can open (the encrypted data key). The worker uses the ready screwdriver to assemble the job (encrypt the data), immediately throws the ready screwdriver into a shredder (zeroizes plaintext from memory), and keeps only the sealed lockbox alongside the finished assembly. When the job needs to be disassembled later, the worker hands the sealed lockbox back to the foreman, who opens it inside the master chest and hands back a fresh ready screwdriver. The master chest never leaves the workshop — that is the essence of GenerateDataKey plus Decrypt in every envelope-encryption code path.

Analogy 2: The Kitchen Recipe Card Pinned to the Dish (Encryption Context as AAD)

Encryption context is like a recipe card pinned to the dish when food is sealed for storage. The card does not hide anything secret — anyone can read "Chicken, Tenant A, 2026-04-20". But when the dish is reopened later, the sous-chef must present the exact same card. If the card reads "Tenant B" or the date is wrong, the tamper-evident seal (AES-GCM AAD validation) breaks and the dish is refused, even if the sous-chef has the right key. That is exactly what encryption context does on Encrypt/Decrypt: the key/value pairs travel in CloudTrail as plaintext for audit, but they are baked into the AES-GCM authentication tag, so decrypting with a different encryption context fails with InvalidCiphertextException.

Analogy 3: The Electrician's Tool Box Keyed to a Specific Job (KMS Grants)

A grant is like giving an electrician a temporary toolbox key that only opens the toolbox during a specific job — say, "rewire Apartment 3B between 9 a.m. and 5 p.m. today". The electrician cannot take the toolbox home, cannot open the toolbox after 5 p.m., and cannot use it for a different apartment. When the job is done, the grant is retired and the key no longer works. AWS KMS grants do the same thing in code: when Amazon EC2 attaches an encrypted EBS volume, it creates a grant scoped to exactly that volume, exactly that AWS KMS key, exactly the Decrypt and GenerateDataKeyWithoutPlaintext actions — temporary, narrow, and revocable without editing the main key policy.

Analogy 4: The Postal System with Tamper-Evident Envelopes (Asymmetric Sign/Verify and Digital Signatures)

Asymmetric AWS KMS encryption is like the postal system with tamper-evident wax seals and counter-signatures. The sender (private key holder, inside AWS KMS) presses a unique wax seal onto the envelope — only their signet ring can produce that exact impression. The recipient (anyone with the public key) can inspect the seal and confirm it matches the sender's signet without ever having the signet themselves. That is kms:Sign producing a signature, and kms:Verify (or any library that accepts the public key from kms:GetPublicKey) confirming it. The private key never leaves AWS KMS — your code only ever sees the public half when you need offline verification.

When you call GenerateDataKey in SDK code, picture the workshop tool chest — the master never leaves, only the single-use screwdriver does a round trip. When you debug an InvalidCiphertextException after a cross-service decrypt, picture the recipe card — the encryption context must match byte-for-byte. When you review IAM and a service unexpectedly needs AWS KMS access, check for a grant (the electrician's temporary toolbox key) before adding a permanent key-policy statement. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping

The Core AWS KMS Encryption APIs a Developer Calls

AWS KMS exposes a small set of APIs that every DVA-C02 candidate should be able to recognize and match to a scenario. The four most-tested are Encrypt, Decrypt, GenerateDataKey, and ReEncrypt.

kms:Encrypt — Direct Encryption Up to 4 KB

kms:Encrypt encrypts plaintext directly with an AWS KMS key and returns ciphertext. The plaintext must be at most 4,096 bytes (4 KB). That hard limit makes kms:Encrypt suitable only for small secrets: OAuth tokens, database passwords before storage in AWS Systems Manager Parameter Store SecureString (which itself calls kms:Encrypt), API keys, small configuration blobs, or short session identifiers.

A minimal call in the AWS SDK for JavaScript (v3) looks like this:

const resp = await kms.send(new EncryptCommand({
  KeyId: "alias/app-secrets",
  Plaintext: Buffer.from("super-secret-value"),
  EncryptionContext: { Service: "billing-api", TenantId: "acme-corp" }
}));
// resp.CiphertextBlob is an opaque byte array; store it and call Decrypt later

Anything larger than 4 KB throws ValidationException before the request even reaches the AWS KMS HSM.

kms:Decrypt — Reversing Encrypt and Unwrapping Data Keys

kms:Decrypt takes a ciphertext blob produced either by kms:Encrypt or by kms:GenerateDataKey and returns the plaintext. The AWS KMS key is determined from metadata embedded in the ciphertext blob, which is why you do not have to pass KeyId on Decrypt (though you should — see the trap below). If the call was made with an encryption context, the same encryption context must be presented on Decrypt or AWS KMS returns InvalidCiphertextException.

kms:GenerateDataKey — The Workhorse of Envelope Encryption

kms:GenerateDataKey is the AWS KMS API that makes bulk encryption scale. It returns a symmetric data key (typically AES_256) in two forms in a single response:

  • Plaintext — the raw 32-byte AES key you use locally to encrypt data with, for example, AES-256-GCM.
  • CiphertextBlob — the same data key encrypted under the AWS KMS key; this is what you persist alongside the ciphertext.

A typical envelope-encryption function looks like:

// 1. Ask KMS for a fresh data key
const dk = await kms.send(new GenerateDataKeyCommand({
  KeyId: "alias/customer-data",
  KeySpec: "AES_256",
  EncryptionContext: { TenantId: tenantId }
}));

// 2. Encrypt the large payload locally with AES-256-GCM using dk.Plaintext
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv("aes-256-gcm", dk.Plaintext, iv);
const ciphertext = Buffer.concat([cipher.update(largePayload), cipher.final()]);
const tag = cipher.getAuthTag();

// 3. Zeroize plaintext data key; persist ciphertext + IV + tag + encrypted data key
dk.Plaintext.fill(0);
await s3.send(new PutObjectCommand({
  Bucket: bucket, Key: objectKey,
  Body: ciphertext,
  Metadata: {
    "x-amz-meta-iv": iv.toString("base64"),
    "x-amz-meta-tag": tag.toString("base64"),
    "x-amz-meta-edk": dk.CiphertextBlob.toString("base64")
  }
}));

On read, the code fetches the encrypted data key from object metadata, calls kms:Decrypt once to unwrap it, decrypts the payload locally, and zeroizes the plaintext data key again.

kms:GenerateDataKeyWithoutPlaintext — Offline Encrypt-Only Paths

kms:GenerateDataKeyWithoutPlaintext returns only the encrypted data key, never the plaintext version. It is designed for systems that collect ciphertext in a pre-generated way — for example, a fleet of IoT devices that each receive a pre-wrapped data key and use it only to encrypt data and ship ciphertext to a central hub, never to decrypt anything themselves. The producer side of such a pipeline needs no decrypt capability, which matches the least-privilege model for device fleets.

kms:ReEncrypt — Rotate Ciphertext Without Exposing Plaintext

kms:ReEncrypt takes ciphertext encrypted under one AWS KMS key and re-encrypts it under a second AWS KMS key (or the same key with a different encryption context) — without the plaintext ever leaving AWS KMS. This is the API you use to rotate encrypted data to a new key after a security event, when migrating from an AWS-managed key to a customer-managed key, or when replicating ciphertext to a new AWS Region with a different key. The caller needs kms:ReEncryptFrom on the source key and kms:ReEncryptTo on the destination key.

On DVA-C02, answer choices that propose calling kms:Encrypt on a 1 MB file, a 10 MB Amazon S3 object, or a 100 MB backup file are wrong. kms:Encrypt rejects anything larger than 4,096 bytes with ValidationException. The right pattern is envelope encryption with kms:GenerateDataKey: get a data key, encrypt the large payload locally with AES-256-GCM, store the encrypted data key alongside the ciphertext. Reference: https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html

Envelope Encryption Pattern in SDK Code

Envelope encryption is the single most common AWS KMS encryption pattern in developer code, and DVA-C02 expects fluency with the step-by-step flow.

The Five-Step Flow

  1. Request a fresh data key. Call kms:GenerateDataKey with KeyId set to your AWS KMS key ARN or alias, KeySpec: AES_256, and an EncryptionContext that identifies the logical object being protected (for example, { TenantId, DocumentId }).
  2. Encrypt locally. Use the Plaintext data key with a local AES-256-GCM implementation in your preferred language (Node.js crypto, Python cryptography, Java Cipher, Go crypto/cipher).
  3. Persist ciphertext + metadata. Store the AES-GCM ciphertext, the 12-byte IV, the 16-byte authentication tag, and the CiphertextBlob (encrypted data key) together. Object metadata on Amazon S3, attribute columns on Amazon DynamoDB, or a wrapping struct in Amazon Kinesis records are all common homes.
  4. Zeroize plaintext. Overwrite the Plaintext buffer with zeros and drop any references. Languages with garbage collection cannot guarantee this, but best-effort zeroization shortens the window where plaintext lives in process memory.
  5. On decrypt, reverse the flow. Fetch the encrypted data key, call kms:Decrypt with the same encryption context, use the unwrapped plaintext data key to decrypt the payload with AES-256-GCM (verifying the authentication tag), zeroize again.

Why It Scales

A single GenerateDataKey call protects megabytes, gigabytes, or terabytes of payload. AWS KMS only handles 32 bytes of key material per call, so a single customer-managed AWS KMS key can serve tens of thousands of payload-encrypting calls per second across your fleet without AWS KMS ever becoming the bottleneck. The AES-256-GCM bulk encryption happens inside your own process, using CPU cycles you already pay for.

Why It Is Safer Than kms:Encrypt-per-call

Calling kms:Encrypt for every chunk of a large payload would (1) multiply AWS KMS request volume and cost by the chunk count, (2) expose you to AWS KMS throttling for hot objects, and (3) still hit the 4 KB limit per call. Envelope encryption solves all three.

  1. kms:GenerateDataKey{ Plaintext, CiphertextBlob }.
  2. AES-256-GCM encrypt payload with Plaintext.
  3. Store ciphertext + IV + tag + CiphertextBlob together.
  4. Zeroize Plaintext immediately after use.
  5. On read: kms:Decrypt(CiphertextBlob, EncryptionContext) → plaintext data key → AES-256-GCM decrypt → zeroize.

Reference: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping

Encryption Context — Additional Authenticated Data (AAD) Bound to Ciphertext

Encryption context is one of AWS KMS encryption's most developer-relevant features and a common DVA-C02 exam target.

What It Is

An encryption context is a non-secret key/value map (strings only) that you pass on any AWS KMS encrypt, decrypt, generate-data-key, or re-encrypt call. AWS KMS treats it as Additional Authenticated Data (AAD) for the AES-GCM cipher that protects the ciphertext blob or data key. That means:

  • The encryption context itself is not secret — it is logged to AWS CloudTrail in plaintext, which makes it perfect for auditing "who decrypted what for which tenant".
  • On decrypt, the caller must supply the exact same encryption context that was used during encryption, or AWS KMS returns InvalidCiphertextException.
  • The encryption context is bound cryptographically to the ciphertext — swapping two ciphertexts between tenants or between object keys does not work.

Patterns That Use It Well

  • Multi-tenant isolation: { TenantId: "acme-corp" }. A bug that tries to decrypt Tenant A's ciphertext while inside Tenant B's request path fails at AWS KMS.
  • Object identity binding: { BucketName: "invoices", ObjectKey: "2026/04/invoice-123.pdf" }. Moving ciphertext to a different object key invalidates decrypt.
  • Purpose binding: { Purpose: "session-token" } vs { Purpose: "refresh-token" }. Prevents accidental reuse across contexts.

Encryption Context in AWS Service Integrations

Many AWS services set encryption context automatically:

  • AWS Lambda environment variables use { "aws:lambda:FunctionName": "<function-name>" } so a different function cannot decrypt the same environment variable even with the same IAM permission.
  • Amazon S3 SSE-KMS uses { "aws:s3:arn": "arn:aws:s3:::bucket/key" }.
  • AWS Secrets Manager uses { "SecretARN": ..., "SecretVersionId": ... }.

You can observe these in AWS CloudTrail Decrypt events, which is the DVA-C02 way to debug "why did this Decrypt succeed or fail".

A classic DVA-C02 trap: the scenario encrypts with { TenantId: "Acme" } and decrypts with { tenantId: "Acme" } (lowercase key). The call fails with InvalidCiphertextException. Encryption context key/value pairs are case-sensitive and must match exactly on decrypt. Order of keys does not matter, but spelling and casing do. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/encrypt_context.html

AWS KMS in the AWS SDK — Service Integrations That Do the Work for You

Most application code never calls GenerateDataKey directly. Instead, the developer passes AWS KMS parameters to an AWS service SDK call and the service performs envelope encryption under the hood.

Amazon S3 — SSE-S3, SSE-KMS, SSE-C, and DSSE-KMS via PutObject

On PutObject, the developer picks server-side encryption via SDK parameters:

// SSE-S3 (AES-256 managed entirely by S3, default since Jan 2023)
await s3.send(new PutObjectCommand({
  Bucket, Key, Body, ServerSideEncryption: "AES256"
}));

// SSE-KMS with a specific AWS KMS key and encryption context
await s3.send(new PutObjectCommand({
  Bucket, Key, Body,
  ServerSideEncryption: "aws:kms",
  SSEKMSKeyId: "alias/customer-data",
  SSEKMSEncryptionContext: Buffer.from(JSON.stringify({
    TenantId: "acme-corp"
  })).toString("base64"),
  BucketKeyEnabled: true
}));

// DSSE-KMS — two independent layers of server-side encryption
await s3.send(new PutObjectCommand({
  Bucket, Key, Body,
  ServerSideEncryption: "aws:kms:dsse",
  SSEKMSKeyId: "alias/customer-data"
}));

// SSE-C — customer-provided key bytes on every request
await s3.send(new PutObjectCommand({
  Bucket, Key, Body,
  SSECustomerAlgorithm: "AES256",
  SSECustomerKey: customerKeyBytes,
  SSECustomerKeyMD5: md5OfCustomerKey
}));

On GetObject with SSE-KMS, you do nothing special — Amazon S3 calls kms:Decrypt for you, using the caller's IAM principal, which must have kms:Decrypt permission on the AWS KMS key either via IAM policy or via the AWS KMS key policy's IAM delegation.

BucketKeyEnabled: true is a developer-relevant optimization: Amazon S3 caches a short-lived bucket-level intermediate key and cuts AWS KMS request volume by roughly 99%, preventing throttling on hot buckets while keeping the AWS CloudTrail audit trail.

Amazon DynamoDB — At-Rest Always On

Amazon DynamoDB tables are always encrypted at rest. The developer only picks the key:

await ddb.send(new CreateTableCommand({
  TableName: "Orders",
  // ...
  SSESpecification: {
    Enabled: true,
    SSEType: "KMS",
    KMSMasterKeyId: "alias/dynamodb-orders"
  }
}));

Default is the AWS-owned key (free, no CloudTrail audit). Specifying SSEType: "KMS" with an alias points to either aws/dynamodb (AWS-managed) or a customer-managed key. For field-level encryption inside items, use the Amazon DynamoDB Encryption Client (below).

Amazon SQS and Amazon SNS — SSE-KMS on the Queue or Topic

Both Amazon SQS and Amazon SNS support SSE with an AWS KMS key. On the SDK, you set the KmsMasterKeyId attribute at queue or topic creation, and the service handles envelope encryption for every message. Encryption context includes the queue or topic ARN.

AWS Lambda Environment Variable Encryption

Lambda environment variables are encrypted at rest by default with an AWS-managed AWS KMS key (aws/lambda). For additional protection beyond the default, enable the "Helpers for encryption in transit" option in the Lambda console or via the SDK, which encrypts the environment variable value a second time with a customer-managed AWS KMS key and requires your function code to decrypt it explicitly at cold start:

import base64, boto3, os
kms = boto3.client("kms")

ENCRYPTED = os.environ["DB_PASSWORD"]
DECRYPTED = kms.decrypt(
    CiphertextBlob=base64.b64decode(ENCRYPTED),
    EncryptionContext={"LambdaFunctionName": os.environ["AWS_LAMBDA_FUNCTION_NAME"]}
)["Plaintext"].decode("utf-8")

The encryption context { LambdaFunctionName: ... } is mandatory and must match the function name, which means a copy of the environment variable pasted into a different function cannot be decrypted — a useful cross-function isolation property.

Amazon CloudWatch Logs Encryption

Log groups can be encrypted with a customer-managed AWS KMS key via AssociateKmsKey:

await logs.send(new AssociateKmsKeyCommand({
  logGroupName: "/aws/lambda/my-function",
  kmsKeyId: "arn:aws:kms:us-east-1:123456789012:key/..."
}));

The AWS KMS key policy must allow logs.<region>.amazonaws.com to use the key via a kms:ViaService condition, otherwise ingestion fails silently.

A common DVA-C02 mistake is trying to call kms:Encrypt on an Amazon S3 object before PutObject. That is wrong for two reasons: (1) it only works for objects under 4 KB, and (2) Amazon S3 already handles envelope encryption when you pass ServerSideEncryption: "aws:kms" and SSEKMSKeyId. The right pattern is let the service do it — pass the AWS KMS parameters on the service SDK call (PutObject, PutMessage, PutRecord) and Amazon S3, Amazon SQS, or Amazon Kinesis will call AWS KMS for you. Reference: https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html

Client-Side Encryption — AWS Encryption SDK and DynamoDB Encryption Client

For workloads that must encrypt data before it leaves the application process (so that the AWS service never sees plaintext), AWS publishes two official client-side libraries.

AWS Encryption SDK

The AWS Encryption SDK is a general-purpose client-side encryption library available in Java, Python, C, JavaScript, and .NET. It wraps AWS KMS envelope encryption behind a simple encrypt/decrypt interface, handles serialization of the encrypted data key and metadata into a portable ciphertext format, and supports advanced features like multiple wrapping keys (for cross-Region or multi-party decrypt), key commitment (to defend against decryption-oracle attacks), and caching data keys for throughput.

A minimal Python example:

import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy
from aws_encryption_sdk.identifiers import AlgorithmSuite

client = aws_encryption_sdk.EncryptionSDKClient(
    commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)
kms_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(
    key_ids=["arn:aws:kms:us-east-1:123456789012:key/..."]
)

ciphertext, header = client.encrypt(
    source=b"sensitive bytes",
    key_provider=kms_provider,
    encryption_context={"TenantId": "acme-corp"}
)

Client-side encryption means Amazon S3, Amazon DynamoDB, or any other destination sees only the opaque ciphertext — even a compromised AWS operator cannot read the original bytes.

Amazon DynamoDB Encryption Client

The Amazon DynamoDB Encryption Client (now part of the AWS Database Encryption SDK) performs per-attribute field-level encryption and signing on Amazon DynamoDB items before PutItem and after GetItem. You declare which attributes are encrypted, which are signed-but-not-encrypted (so they can still drive queries), and which are plaintext. The library fetches data keys from AWS KMS and handles the envelope pattern, producing a fully client-side-encrypted item that Amazon DynamoDB stores without ever seeing the sensitive fields.

Typical attribute classifications:

  • ENCRYPT_AND_SIGN — sensitive values (SSN, credit card).
  • SIGN_ONLY — query keys that must remain in plaintext but cannot be tampered with.
  • DO_NOTHING — completely public values.

When to Pick Client-Side Over Server-Side

Pick client-side when the threat model distrusts the AWS service itself, regulation forbids AWS from having plaintext access under any scenario, or the data must be re-encrypted at a different layer (for example, end-to-end between mobile clients). Pick server-side (SSE-KMS, DSSE-KMS, DynamoDB at-rest encryption) when you only need at-rest protection and you trust the AWS service's envelope encryption to handle everything.

KMS Grants — Delegated, Narrowly Scoped Permissions

Grants are an AWS KMS encryption feature specifically designed for programmatic, temporary permission delegation. On DVA-C02, they show up in scenarios involving attached volumes, ephemeral tasks, and cross-principal workflows.

What a Grant Is

A grant is a permission document on an AWS KMS key that:

  • Allows a specific grantee principal (IAM role, user, or AWS service) to perform specific AWS KMS actions (Decrypt, Encrypt, GenerateDataKey, ReEncryptFrom/ReEncryptTo, etc.).
  • Is scoped to specific grant constraints — most importantly EncryptionContextEquals or EncryptionContextSubset, which bind the grant to operations performed with a matching encryption context.
  • Can be retired or revoked at any time by the grantor, the grantee (if permitted), or by the grant's retiring principal.
  • Takes effect within a few minutes (eventually consistent) and is visible in AWS CloudTrail.

Why Grants Are Used Instead of Key Policy Edits

Key policies are long-lived, globally scoped, and require kms:PutKeyPolicy permission (typically held only by security admins). Grants are:

  • Temporary: they can be created and retired by application code or by AWS services.
  • Narrow: constrained to specific encryption contexts and specific grantees.
  • Non-blocking: they do not require editing the main key policy, which reduces change-management friction.

Common Grant Patterns

  • Amazon EBS attaching to Amazon EC2: Amazon EBS creates a grant on the AWS KMS key scoped to exactly the volume being attached; the grant allows kms:Decrypt and kms:GenerateDataKeyWithoutPlaintext for that volume only.
  • AWS Lambda@Edge needing decrypt across Regions: a grant on a multi-Region key replica in each edge region, scoped to the Lambda execution role.
  • Amazon EMR reading encrypted Amazon S3 data: a grant that allows the EMR cluster role to decrypt only objects with a matching encryption context.

If you find yourself wanting to edit the AWS KMS key policy every time a new AWS Lambda function or container task needs temporary access, you probably want a grant instead. Grants are designed to be issued and retired by code. They show up in kms:CreateGrant CloudTrail events, so audit is preserved. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/grants.html

Asymmetric AWS KMS Keys — Sign, Verify, Encrypt, Decrypt

Asymmetric AWS KMS keys are RSA or ECC key pairs where the public key can be exported and distributed but the private key stays inside AWS KMS forever.

kms:Sign and kms:Verify

For digital signatures:

const sig = await kms.send(new SignCommand({
  KeyId: "alias/doc-signer",
  Message: documentHash,
  MessageType: "DIGEST",
  SigningAlgorithm: "RSASSA_PSS_SHA_256"
}));

// Later, anywhere with the public key:
const ok = await kms.send(new VerifyCommand({
  KeyId: "alias/doc-signer",
  Message: documentHash,
  MessageType: "DIGEST",
  SigningAlgorithm: "RSASSA_PSS_SHA_256",
  Signature: sig.Signature
}));
// ok.SignatureValid === true

Typical use cases: signing JWTs, signing software artifacts, signing audit records for tamper-evidence, signing certificate requests, code signing for AWS Lambda.

Offline Verification with kms:GetPublicKey

For high-volume verification paths that should not hit AWS KMS on every call, fetch the public key once with kms:GetPublicKey and verify locally using any standard crypto library. The private key never leaves AWS KMS; only the public half is distributed.

Asymmetric Encrypt/Decrypt

Asymmetric AWS KMS keys can also be used for kms:Encrypt/kms:Decrypt with RSAES_OAEP_SHA_256. A common pattern: a sender that has only the public key encrypts a small payload (still 4 KB max) that only the holder of the private key — AWS KMS — can decrypt. Useful for one-way secret injection from systems that should never have decrypt authority.

Asymmetric Key Rotation Is Manual

Unlike symmetric AWS KMS keys, asymmetric keys cannot use automatic rotation. To rotate, you create a new asymmetric AWS KMS key, update the alias to point at the new key, redistribute the new public key to verifiers, and keep the old key around long enough for outstanding signatures to verify.

Multi-Region Keys — Same Key ID Across AWS Regions

Multi-Region keys are an AWS KMS encryption feature aimed directly at developers of globally distributed applications.

What Multi-Region Keys Solve

In a single-Region design, ciphertext encrypted in us-east-1 cannot be decrypted in eu-west-1 without a cross-Region AWS KMS call, which introduces latency, cost, and a cross-Region failure dependency. Multi-Region keys are a set of related AWS KMS keys — one primary and one or more replicas — that share the same key ID and the same underlying key material, but live in different AWS Regions. Ciphertext encrypted with one replica can be decrypted by any other replica without any cross-Region AWS KMS call.

How to Create and Use Them

// Create primary in us-east-1
const primary = await kms.send(new CreateKeyCommand({
  MultiRegion: true,
  KeyUsage: "ENCRYPT_DECRYPT"
}));

// Replicate to eu-west-1 (separate AWS KMS client in that Region)
await kmsEu.send(new ReplicateKeyCommand({
  KeyId: primary.KeyMetadata.KeyId,
  ReplicaRegion: "eu-west-1"
}));

All replicas share the key ID (the suffix, not the ARN); their ARNs differ by Region. Ciphertext produced in us-east-1 includes metadata that lets any replica decrypt it — your code simply calls the local replica's ARN on Decrypt.

When to Use Them

  • Global Amazon DynamoDB Global Tables with customer-managed key encryption — each Region's replica uses its local multi-Region key replica, so cross-Region failover does not require cross-Region AWS KMS calls.
  • Amazon S3 Cross-Region Replication with SSE-KMS — the source bucket and destination bucket each use their local replica.
  • Active-active applications where the same ciphertext must be readable in multiple Regions simultaneously.

Multi-Region keys are not the same as automatic cross-Region key sharing. Each replica is an independent AWS KMS key with its own key policy, its own grants, its own CloudTrail trail, and its own pricing ($1/month per replica per Region). They just happen to share key material.

AWS KMS Request Quotas — Shared Throttling Developers Must Plan For

AWS KMS enforces per-Region, per-account API rate limits that are shared across all AWS services in the account, which is a recurring DVA-C02 troubleshooting scenario.

The Quotas at a Glance

Per-Region, per-account, the symmetric cryptographic operation quota is (approximately, as of 2025):

  • 10,000 requests per second in most AWS Regions for Encrypt, Decrypt, GenerateDataKey, GenerateDataKeyWithoutPlaintext, and ReEncrypt (shared bucket).
  • 30,000 requests per second in some large Regions (us-east-1, us-west-2, eu-west-1).
  • Separate quotas for asymmetric operations (Sign, Verify, GetPublicKey), RSA operations, and ECC operations, each with lower per-second limits.

Why "Shared" Matters

That 10,000 req/s is shared across every AWS service in the account. Amazon S3 SSE-KMS calls, Amazon DynamoDB at-rest key lookups, AWS Lambda environment variable decrypts at cold start, Amazon SQS message puts to encrypted queues, your own application code — all count against the same bucket. A noisy Amazon S3 workload can throttle your Amazon DynamoDB workload, and vice versa.

Mitigations a Developer Implements

  • Enable Amazon S3 Bucket Keys on every SSE-KMS bucket — cuts AWS KMS request volume ~99% by caching a short-lived bucket-level intermediate key.
  • Use envelope encryption with long-lived data keys in application code (AWS Encryption SDK data key caching) — one GenerateDataKey call can protect thousands of items before the data key is rotated.
  • Use provisioned concurrency for AWS Lambda functions that decrypt on cold start — fewer cold starts, fewer decrypts.
  • Request a quota increase via AWS Service Quotas for high-throughput workloads.
  • Distribute across AWS Regions for global workloads — each Region has its own quota bucket.

DVA-C02 scenarios sometimes describe "AWS KMS ThrottlingException appeared out of nowhere; we did not change our code". The trap answer is to blame the application. The real answer is usually another workload in the same account (a new Amazon S3 bucket with SSE-KMS, a newly encrypted AWS Lambda environment variable, a migration loading encrypted Amazon DynamoDB) consumed the shared per-Region quota. Enable Amazon S3 Bucket Keys and request a quota increase. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/requests-per-second.html

AWS KMS Key Rotation — Automatic, Manual, and ReEncrypt Patterns

Rotation is both a DVA-C02 exam fact and a developer responsibility.

Automatic Rotation for Symmetric AWS KMS Keys

For customer-managed symmetric AWS KMS keys with AWS-owned key material, AWS KMS rotates the underlying cryptographic material every 365 days by default (configurable between 90 and 2,560 days as of 2024). The key ID and ARN do not change, old key material is retained so previously encrypted data is still decryptable, and no application code changes are required. AWS-managed keys rotate yearly automatically; you cannot disable this.

Manual Rotation for Asymmetric and Imported-Material Keys

Asymmetric keys and keys with imported (BYOK) key material must be rotated manually:

  1. Create a new AWS KMS key.
  2. Update the alias (alias/app-v1 → points at the new key).
  3. For ciphertext that must be protected by the new key's material, call kms:ReEncrypt to re-wrap without exposing plaintext.

Applications that reference the alias continue working without redeployment; applications that hard-code the old key ARN need a config change.

ReEncrypt in Code

const resp = await kms.send(new ReEncryptCommand({
  CiphertextBlob: oldCiphertext,
  SourceKeyId: "alias/app-v1-old",
  DestinationKeyId: "alias/app-v1-new",
  SourceEncryptionContext: { TenantId: "acme-corp" },
  DestinationEncryptionContext: { TenantId: "acme-corp" }
}));
// resp.CiphertextBlob is the same plaintext re-wrapped under the new key

The caller needs kms:ReEncryptFrom on the source and kms:ReEncryptTo on the destination. Plaintext never leaves AWS KMS.

  • Automatic rotation: 365 days default, 90–2,560 days configurable, symmetric keys with AWS-owned material only.
  • Asymmetric and imported-material keys: manual rotation only.
  • Key ID and ARN stay the same across automatic rotation.
  • Old key material is retained so previously encrypted data is still decryptable.
  • kms:ReEncrypt re-wraps ciphertext under a new key without exposing plaintext.
  • Reference: https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html

Developer Exam Traps — AWS KMS Encryption on DVA-C02

Expect several of these on every DVA-C02 attempt.

Trap 1: Using kms:Encrypt on Large Payloads

Any answer that calls kms:Encrypt directly on an Amazon S3 object, a multi-MB file, or a streaming payload is wrong. The 4 KB limit is absolute. The right answer is envelope encryption with kms:GenerateDataKey.

Trap 2: Missing or Mismatched Encryption Context on Decrypt

If encrypt included { TenantId: "Acme" } and decrypt includes nothing or { TenantId: "acme" }, AWS KMS returns InvalidCiphertextException. The application log usually blames "bad ciphertext" but the real cause is a context mismatch.

Trap 3: Assuming IAM Alone Grants KMS Access

AWS KMS requires the key policy to delegate to IAM before an IAM policy works. Without the "Enable IAM policies" statement in the key policy, kms:Decrypt in IAM is ignored. DVA-C02 scenarios that show "IAM allows but call fails" almost always hit this.

Trap 4: Trying to Rotate an Asymmetric Key Automatically

Automatic rotation works only for symmetric keys with AWS-owned material. Any scenario mixing "imported key material" or "asymmetric key" with "enable automatic rotation" is pointing at a wrong answer — manual rotation via new key + alias update + ReEncrypt is the right workflow.

Trap 5: Ignoring the Shared KMS Quota Across Services

A workload works in testing and throttles in production not because the workload changed but because another Amazon S3 bucket or Amazon DynamoDB table in the same account started consuming the shared per-Region quota. Enable Amazon S3 Bucket Keys, use data key caching, and request a quota increase.

Trap 6: Forgetting the Lambda Environment Variable Encryption Context

When using Lambda's encryption helper, the kms:Decrypt call inside the function must include EncryptionContext: { LambdaFunctionName: <function-name> }. Forgetting this returns InvalidCiphertextException at cold start, which is a classic Lambda interview question too.

Trap 7: Cross-Region Code Without Multi-Region Keys

Trying to decrypt a ciphertext produced by a us-east-1 AWS KMS key from a service running in eu-west-1 fails — the KMS call must go to the Region that owns the key. The fix is either making the cross-Region call explicitly, or using a multi-Region key so each Region has a local replica with the same material.

Trap 8: Confusing SSE-C with Client-Side Encryption

SSE-C (SSECustomerKey on Amazon S3) is still server-side — Amazon S3 briefly sees the key and the plaintext to perform AES-256 before discarding the key. True client-side encryption uses the AWS Encryption SDK and Amazon S3 never sees plaintext. DVA-C02 distractors sometimes equate the two; they are not the same.

Key Numbers and Must-Memorize Facts for AWS KMS Encryption

  • kms:Encrypt plaintext limit: 4,096 bytes (4 KB).
  • kms:GenerateDataKey returns both plaintext and ciphertext data key in one response.
  • kms:GenerateDataKeyWithoutPlaintext returns only ciphertext — for encrypt-only producers.
  • kms:ReEncrypt re-wraps ciphertext to a new key without exposing plaintext.
  • Encryption context must match byte-for-byte on decrypt (case-sensitive keys and values).
  • AWS KMS customer-managed key cost: USD 1.00/month per key + per-request charges.
  • Automatic rotation default: 365 days, configurable 90–2,560 days, symmetric AWS-owned material only.
  • Per-Region shared quota: ~10,000 req/s in most Regions, ~30,000 req/s in large Regions.
  • Amazon S3 Bucket Keys reduce AWS KMS request volume by ~99%.
  • Multi-Region keys share key ID and key material across Regions; each replica costs $1/month.
  • Lambda env var encryption context: { LambdaFunctionName: <name> }.
  • Key deletion waiting period: 7 to 30 days.
  • Reference: https://docs.aws.amazon.com/kms/latest/developerguide/overview.html

Practice Scenarios — DVA-C02 Mapped Answers

  • "Encrypt a 50 MB video file before uploading to Amazon S3 so Amazon S3 never sees plaintext." → AWS Encryption SDK client-side with a customer-managed AWS KMS key.
  • "Encrypt a 200-byte API key before storing in Amazon DynamoDB." → Direct kms:Encrypt (under 4 KB) with encryption context { TenantId, Purpose }.
  • "Rotate ciphertext to a new customer-managed key after a compromise without exposing plaintext in application memory." → kms:ReEncrypt from old to new key.
  • "Ensure an AWS Lambda environment variable decrypt works only inside that specific function." → Enable encryption helper, decrypt with EncryptionContext: { LambdaFunctionName: $AWS_LAMBDA_FUNCTION_NAME }.
  • "Allow an Amazon ECS task to decrypt with an AWS KMS key only while processing a specific Amazon SQS message." → KMS grant scoped to the task role with EncryptionContextEquals.
  • "Amazon S3 SSE-KMS bucket is throttling at 8,000 req/s." → Enable Amazon S3 Bucket Keys on the bucket.
  • "Sign a JWT with a private key that can never leave AWS." → Asymmetric AWS KMS key with kms:Sign using RSASSA_PSS_SHA_256.
  • "Decrypt the same ciphertext in us-east-1 and eu-west-1 without cross-Region calls." → Multi-Region key with a replica in each Region.
  • "IoT device must encrypt telemetry but must never decrypt anything." → kms:GenerateDataKeyWithoutPlaintext per device, use returned ciphertext blob as the wrapped data key.
  • "Field-level encryption of SSN inside an Amazon DynamoDB item, but CustomerId must remain queryable." → Amazon DynamoDB Encryption Client with ENCRYPT_AND_SIGN for SSN and SIGN_ONLY for CustomerId.

FAQ — AWS KMS Encryption Top Questions for DVA-C02

Q1: Why does kms:Encrypt fail on a 100 KB file and what should I use instead?

kms:Encrypt has a hard 4,096-byte (4 KB) plaintext limit; anything larger is rejected with ValidationException before the cryptographic operation runs. The correct pattern for larger payloads is envelope encryption with kms:GenerateDataKey: request a fresh AES-256 data key from AWS KMS, use the returned plaintext data key to encrypt the payload locally with AES-256-GCM, persist the returned encrypted data key alongside the ciphertext, and zeroize the plaintext data key from memory. On decrypt, call kms:Decrypt on the encrypted data key, unwrap locally, and decrypt the payload. This scales AWS KMS encryption to gigabyte-class payloads while AWS KMS only handles 32 bytes per call.

Q2: What is encryption context and why does every AWS KMS encryption example include it?

Encryption context is a non-secret key/value map passed on every AWS KMS encrypt, decrypt, generate-data-key, and re-encrypt call. AWS KMS treats it as Additional Authenticated Data (AAD) for the AES-GCM cipher that protects the ciphertext blob, so the same context must be presented on decrypt or the call fails with InvalidCiphertextException. It serves three developer-important roles: (1) tenant or object binding — ciphertext for Tenant A cannot be decrypted by accidentally invoking a Tenant B code path; (2) audit — because the context is logged to AWS CloudTrail in plaintext, you can ask "who decrypted ciphertext for TenantId=Acme in the last 24 hours?"; (3) defense in depth — IAM can allow the kms:Decrypt call but a bug that swaps tenants still fails cryptographically.

Q3: How do I rotate an AWS KMS key's material without losing access to existing ciphertext?

For customer-managed symmetric AWS KMS keys with AWS-owned material, enable automatic rotation — AWS KMS generates fresh material every 365 days (or a configurable 90–2,560 days), the key ID and ARN do not change, old material is retained so existing ciphertext is still decryptable, and no application code changes. For asymmetric keys or keys with imported BYOK material, rotation is manual: create a new AWS KMS key, update the alias to point at the new key, and for ciphertext that must be re-wrapped under the new material call kms:ReEncrypt — this re-wraps ciphertext under the new key without the plaintext ever leaving AWS KMS. Keep the old key enabled long enough for all outstanding ciphertext to either be re-encrypted or retired.

Q4: What is the difference between SSE-KMS on Amazon S3 and client-side encryption with the AWS Encryption SDK?

SSE-KMS is server-side — your SDK call passes plaintext to Amazon S3 over TLS, Amazon S3 calls kms:GenerateDataKey on your behalf, encrypts the object with the data key, and stores the ciphertext. Amazon S3 briefly processes plaintext inside its own service boundary. You get AWS CloudTrail records of every decrypt and fine-grained key policy control, and you pay for both S3 and AWS KMS requests. Client-side encryption with the AWS Encryption SDK encrypts the object inside your application process before it ever leaves your host; Amazon S3 only stores ciphertext and never sees plaintext even inside its own boundary. Pick SSE-KMS for most at-rest scenarios because it is simpler and integrates with every AWS service. Pick client-side encryption when regulation or threat model requires that AWS cannot read the plaintext under any circumstances, or when you need end-to-end encryption from a mobile client through Amazon S3 to a downstream consumer.

Q5: Why is my application suddenly hitting AWS KMS ThrottlingException even though my own request rate did not change?

AWS KMS enforces a per-Region, per-account request quota that is shared across every AWS service in the account — Amazon S3 SSE-KMS calls, Amazon DynamoDB at-rest key lookups, AWS Lambda environment variable decrypts, Amazon SQS encrypted queue operations, and your own application calls all draw from the same ~10,000 req/s bucket (up to ~30,000 in large Regions). A newly deployed Amazon S3 workload, a large Amazon DynamoDB import, or a burst of Lambda cold starts can consume the quota and throttle your previously stable application. Mitigations: enable Amazon S3 Bucket Keys on every SSE-KMS bucket (cuts volume ~99%), use AWS Encryption SDK data key caching in application code to protect many items with one data key, reserve provisioned concurrency for chronic cold-start functions, spread high-volume workloads across multiple AWS Regions (each has its own quota), and request a quota increase via AWS Service Quotas for sustained high throughput.

Q6: How do I let one AWS Lambda function decrypt an environment variable without making the same ciphertext decryptable by a different function?

Enable the Lambda "Helpers for encryption in transit" option, which encrypts the environment variable with a customer-managed AWS KMS key and requires your code to decrypt at cold start. Lambda automatically sets the encryption context to { LambdaFunctionName: <function-name> }, so your kms:Decrypt call must pass the same EncryptionContext: { LambdaFunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME }. If someone copies the ciphertext into a different Lambda function, the decrypt fails with InvalidCiphertextException because the function name embedded in the encryption context will not match, even if the IAM role happens to have kms:Decrypt on the same key. Combine this with an AWS KMS key policy that restricts decrypt to the specific function's execution role for belt-and-suspenders isolation.

Q7: When should I use a KMS grant instead of editing the AWS KMS key policy?

Use a grant for temporary, programmatic, narrowly scoped permissions — for example, an Amazon EBS volume attach that needs decrypt only for that volume, an Amazon ECS task that needs decrypt only while processing a specific batch, or a cross-service integration that needs short-lived delegated access. Grants are created and retired by code or by AWS services via kms:CreateGrant and kms:RetireGrant, they support encryption-context constraints that bind them to specific operations, they do not require editing the main key policy (which usually needs kms:PutKeyPolicy held only by security admins), and they appear in AWS CloudTrail for audit. Use the key policy for long-lived, account-wide trust relationships — for example, delegating all IAM-based authorization to the account's IAM policies, or granting a specific production role permanent decrypt access. Grants are a developer tool; key policies are a platform governance tool.

Q8: What do multi-Region keys do that cross-Region KMS calls cannot?

A multi-Region key is a set of related AWS KMS keys — one primary and one or more replicas — that share the same key ID and the same underlying key material across AWS Regions. Ciphertext produced in one Region can be decrypted by any replica in any other Region without any cross-Region AWS KMS call, which eliminates cross-Region latency and removes a cross-Region failure dependency. This matters for Amazon DynamoDB Global Tables with customer-managed key encryption, Amazon S3 Cross-Region Replication with SSE-KMS, and active-active applications where the same ciphertext must be readable from multiple Regions simultaneously. Cross-Region KMS calls still work without multi-Region keys, but every decrypt in the remote Region incurs the latency of the round trip and fails if the primary Region or the network path is down — exactly the single point of failure multi-Region keys remove. Each replica is still an independent key with its own key policy, its own grants, and $1/month pricing.

Further Reading

官方資料來源