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

AWS KMS 與信封加密

6,400 字 · 約 32 分鐘閱讀 ·

完整掌握 DVA-C02 所需的 AWS KMS 加密知識:Encrypt/Decrypt/GenerateDataKey API、SDK 中的信封加密模式、加密上下文作為 AAD、PutObject 的 S3 SSE 選項、Lambda 環境變數加密、用戶端加密、Grants、多區域金鑰、Sign/Verify、請求配額——含程式碼範例、考試陷阱與開發者導向類比。

立即做 20 題練習 → 免費 · 不用註冊 · DVA-C02

AWS KMS 加密是 AWS Key Management Service(AWS KMS)面向開發者的 API 與 SDK 模式集合,讓應用程式程式碼能夠在不接觸原始金鑰位元組的前提下,完成資料的加密、解密、簽章、驗章與金鑰輪換。對於 DVA-C02 考生而言,AWS KMS 加密不是在儲存主控台上勾一個選項——而是你實際撰寫的程式碼kms:Encrypt 用於 4 KB 以下的小型機密、kms:GenerateDataKey 用於信封加密模式以保護數 GB 的酬載、kms:ReEncrypt 用於在不解密明文的情況下輪換金鑰、kms:Signkms:Verify 用於數位簽章,以及在每次呼叫中作為附加驗證資料(AAD)的加密上下文字串。本指南涵蓋開發者會接觸到的所有 AWS KMS 加密 API、在 PutObject 上切換 SSE-KMS 的 SDK 參數、Lambda 環境變數加密輔助工具、使用 AWS Encryption SDK 與 Amazon DynamoDB Encryption Client 的用戶端加密、用於委派臨時存取的 KMS Grants、跨區域程式碼路徑的多區域金鑰,以及若未事先規劃便會在高吞吐量服務上造成問題的共享節流配額。

在 DVA-C02 考試中,領域二(「使用 AWS 服務進行開發」)與領域三(「部署」)都要求考生能在 SDK 程式碼中做出流暢的 AWS KMS 加密決策。考試情境常問:「哪個 AWS KMS API 呼叫能有效率地保護 20 MB 的檔案?」(是 GenerateDataKey,而非 Encrypt)、「如何將密文與租戶識別碼綁定?」(加密上下文作為 AAD)、「如何在不暴露明文的情況下將密文輪換至新的 AWS KMS 金鑰?」(ReEncrypt)、「Lambda 函式如何解密自己的環境變數?」(KMS 輔助工具搭配 AWS_LAMBDA_FUNCTION_NAME 加密上下文),以及「為什麼我的服務突然在每秒 10,000 個請求時被節流?」(每個區域共享的 AWS KMS 請求配額)。對這些問題具備程式碼等級的信心,AWS KMS 加密就能成為 DVA-C02 的強項,而非時間黑洞。

AWS KMS 加密對開發者來說是什麼?

AWS KMS 加密對開發者而言,是 AWS KMS 的程式化介面——即開發者從 Amazon EC2、AWS Lambda、Amazon ECS、AWS Fargate、AWS App Runner,或任何可執行 AWS SDK 的環境所呼叫的 API、SDK 輔助工具與用戶端函式庫。AWS KMS 本身將金鑰材料保存在硬體安全模組中,絕不將 AWS KMS 金鑰(前身為 customer master key,CMK)釋放至你的程式碼;取而代之,它接受小型請求、在自身邊界內執行密碼學運算,並回傳密文、明文、資料金鑰、簽章或驗章結果。

開發者與 AWS KMS 加密互動時,有六種反覆出現的模式:

  1. 直接呼叫 kms:Encrypt / kms:Decrypt,用於最多 4,096 位元組(4 KB)的小型酬載——適用於機密、token 與小型設定 blob。
  2. 信封加密,透過 kms:GenerateDataKey——這是幾乎所有超過 4 KB 資料的標準模式,也就是說幾乎涵蓋所有正式環境的情況。
  3. kms:ReEncrypt——在不讓明文離開 AWS KMS 的前提下,將密文從一個 AWS KMS 金鑰重新加密至另一個金鑰。
  4. 非對稱操作kms:Signkms:Verifykms:GetPublicKey)——用於數位簽章、文件簽署與 JWT 驗證。
  5. 伺服器端加密整合(Amazon S3 SSE-KMS、Amazon DynamoDB、Amazon SQS、Amazon SNS、AWS Lambda 環境變數),透過 SDK 參數驅動,而非直接呼叫 AWS KMS。
  6. 用戶端加密,使用 AWS Encryption SDK、Amazon S3 Encryption Client 或 Amazon DynamoDB Encryption Client,這些函式庫將 AWS KMS 呼叫封裝在高階的 encrypt/decrypt 方法背後。
  • AWS KMS 金鑰:AWS KMS 內部的邏輯金鑰物件。金鑰材料永不離開 AWS KMS。歷史上也稱為 customer master key(CMK)。
  • 資料金鑰:AWS KMS 按需產生的 128 位元或 256 位元對稱金鑰,用於大量資料加密。GenerateDataKey 同時以明文與密文形式回傳。
  • 信封加密:以資料金鑰加密使用者資料,再以 AWS KMS 金鑰加密該資料金鑰。這是超過 4 KB 資料的預設模式。
  • 加密上下文:在每次 AWS KMS 加密或解密呼叫中傳遞的非機密鍵值對映射。作為附加驗證資料(AAD)使用,解密時必須完全相符。
  • Grant:對 AWS KMS 金鑰許可的臨時性、窄範圍委派。由服務或你自己的程式碼以程式化方式建立。
  • 多區域金鑰:一組分佈於多個 AWS 區域的 AWS KMS 金鑰,共享相同的金鑰 ID 與金鑰材料,用於跨區域程式碼路徑。
  • AWS KMS 請求配額:每區域、每帳號、每金鑰類型的每秒 AWS KMS API 請求上限。在帳號內所有 AWS 服務間共享。
  • 參考:https://docs.aws.amazon.com/kms/latest/developerguide/overview.html

為什麼 AWS KMS 加密對 DVA-C02 至關重要

AWS KMS 加密出現在三個 DVA-C02 領域中。領域二(「使用 AWS 服務進行開發」)測試你是否能在 SDK 程式碼中將 AWS KMS 呼叫正確接入 Amazon S3、Amazon DynamoDB、AWS Lambda 與 Amazon SQS。領域三(「部署」)詢問關於加密部署成品、加密 AWS Lambda 環境變數,以及在 AWS CloudFormation 範本中參考 AWS KMS 金鑰。領域四(「疑難排解與最佳化」)詢問 AWS KMS 節流、加密上下文不符所導致的 InvalidCiphertextException,以及 CloudTrail 偵錯。掌握 AWS KMS 加密,你就在四個考試領域中的三個拿到了穩定分數。

白話文解釋 AWS KMS Encryption for Developers

以下提供四個不同風格的開發者類比,合在一起涵蓋了 DVA-C02 上所有 AWS KMS 加密的概念。

類比一:大廚的主廚秘方盒(程式碼中的信封加密)

想像一間廚房裡有一個主廚秘方盒,牢牢鎖在備餐台上——它非常沉重,永遠不會離開廚房,只有主廚知道密碼。這個秘方盒就是 AWS KMS 金鑰。每道菜開始備料時,學徒廚師(你的應用程式程式碼)向主廚要一把本次專用的醬料瓶(資料金鑰)。主廚從秘方盒裡調出一瓶新醬料,交給學徒兩份:一份是可以直接使用的(明文資料金鑰),另一份是封存在只有主廚秘方盒才能打開的密封罐裡(加密後的資料金鑰)。學徒用那瓶現成的醬料完成備料(加密資料),隨即將用過的醬料瓶沖洗乾淨(清零記憶體中的明文),只保留那個密封罐和做好的料理。之後若需要還原料理,學徒把密封罐交回主廚,主廚在秘方盒內打開它,再給出新的一瓶現成醬料。主廚秘方盒永遠不離廚房——這正是每條信封加密程式碼路徑中,GenerateDataKey 搭配 Decrypt 的本質。

類比二:貼在料理上的食材標籤(加密上下文作為 AAD)

加密上下文就像封存料理時貼上的食材標籤。標籤本身不藏任何秘密——任何人都能看到「雞肉、A 桌客人、2026-04-20」。但當料理被取出時,二廚必須出示完全相同的標籤。若標籤寫的是「B 桌客人」或日期不對,防竄改封條(AES-GCM AAD 驗證)就會失效,料理直接被拒絕,即便二廚拿的是正確的鑰匙也一樣。加密上下文在 EncryptDecrypt 上的作用正是如此:鍵值對以明文記錄至 AWS CloudTrail 供稽核,但同時被烙入 AES-GCM 驗證標籤,因此以不同的加密上下文解密時,會以 InvalidCiphertextException 失敗。

類比三:只限今日特定工程的工具箱鑰匙(KMS Grants)

Grant 就像給水電工一把臨時工具箱鑰匙,這把鑰匙只在特定工程期間有效——例如「今日上午九點至下午五點,負責三樓 B 棟的電路重拉工程」。水電工無法把工具箱帶回家,五點後無法開箱,也無法拿去用在其他棟。工程結束後 grant 退還,鑰匙立刻失效。AWS KMS Grants 在程式碼裡做的是同一件事:當 Amazon EC2 掛載加密的 EBS 磁碟區時,Amazon EBS 建立一個 grant,範圍精確限定在那顆磁碟區、那個 AWS KMS 金鑰,以及 DecryptGenerateDataKeyWithoutPlaintext 這兩個操作——臨時、窄範圍,且可在不修改主要金鑰政策的情況下撤銷。

類比四:帶防偽火漆封印的掛號信(非對稱 Sign/Verify 與數位簽章)

非對稱 AWS KMS 加密就像帶有防偽火漆封印的掛號信。寄件人(AWS KMS 內部的私鑰持有者)在信封上按下獨一無二的火漆印——只有他的印章戒指能壓出那個圖樣。收件人(任何持有公鑰的人)可以檢視封印並確認它符合寄件人的印章,不需要自己擁有印章戒指。這就是 kms:Sign 產生簽章、kms:Verify(或任何接受 kms:GetPublicKey 公鑰的函式庫)確認簽章的過程。私鑰永遠不離開 AWS KMS——你的程式碼在需要離線驗證時,只會看到公開的那一半。

當你在 SDK 程式碼中呼叫 GenerateDataKey 時,想想主廚秘方盒——主廚永不離廚房,只有那瓶單次使用的醬料做了一趟往返。當你在跨服務解密後偵錯 InvalidCiphertextException 時,想想食材標籤——加密上下文必須逐位元組相符。當你審查 IAM 時發現某個服務意外需要 AWS KMS 存取,先檢查是否有 Grant(水電工的臨時工具箱鑰匙),再考慮新增永久的金鑰政策陳述式。參考:https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping

開發者會呼叫的核心 AWS KMS 加密 API

AWS KMS 提供一小組 API,每位 DVA-C02 考生都應能辨識並對應到情境。最常被考到的四個是 EncryptDecryptGenerateDataKeyReEncrypt

kms:Encrypt — 最多 4 KB 的直接加密

kms:Encrypt 直接以 AWS KMS 金鑰加密明文並回傳密文。明文最多 4,096 位元組(4 KB)。這個硬性限制使 kms:Encrypt 僅適用於小型機密:OAuth token、資料庫密碼(在儲存至 AWS Systems Manager Parameter Store SecureString 之前,後者本身也會呼叫 kms:Encrypt)、API 金鑰、小型設定 blob,或簡短的 session 識別碼。

AWS SDK for JavaScript(v3)的最簡呼叫如下:

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 是不透明的位元組陣列;儲存後稍後呼叫 Decrypt

任何超過 4 KB 的資料在請求到達 AWS KMS HSM 之前就會拋出 ValidationException

kms:Decrypt — 反轉 Encrypt 並解包資料金鑰

kms:Decrypt 接受由 kms:Encryptkms:GenerateDataKey 產生的密文 blob 並回傳明文。AWS KMS 金鑰由密文 blob 中嵌入的中繼資料決定,這就是為什麼你不必在 Decrypt 時傳遞 KeyId(不過你應該傳——見下方陷阱)。若呼叫時使用了加密上下文,則解密時必須提供相同的加密上下文,否則 AWS KMS 回傳 InvalidCiphertextException

kms:GenerateDataKey — 信封加密的主力 API

kms:GenerateDataKey 是讓大量加密得以擴展的 AWS KMS API。它在單一回應中以兩種形式回傳對稱資料金鑰(通常為 AES_256):

  • Plaintext — 你在本地用來加密資料的原始 32 位元組 AES 金鑰,例如搭配 AES-256-GCM。
  • CiphertextBlob — 以 AWS KMS 金鑰加密過的同一把資料金鑰;這是你與密文一同持久化儲存的內容。

典型的信封加密函式如下:

// 1. 向 KMS 索取一把新的資料金鑰
const dk = await kms.send(new GenerateDataKeyCommand({
  KeyId: "alias/customer-data",
  KeySpec: "AES_256",
  EncryptionContext: { TenantId: tenantId }
}));

// 2. 在本地以 AES-256-GCM 使用 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. 清零明文資料金鑰;持久化儲存密文 + IV + tag + 加密後的資料金鑰
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")
  }
}));

讀取時,程式碼從物件中繼資料取出加密後的資料金鑰,呼叫一次 kms:Decrypt 解包,在本地解密酬載,並再次清零明文資料金鑰。

kms:GenerateDataKeyWithoutPlaintext — 僅加密的離線路徑

kms:GenerateDataKeyWithoutPlaintext 只回傳加密後的資料金鑰,從不回傳明文版本。它的設計對象是以預先產生密文方式運作的系統——例如一批 IoT 裝置,每台裝置各自收到一把預先封裝好的資料金鑰,只用它來加密資料並將密文傳送至中央集線器,從不自行解密任何東西。這類管線的生產者端不需要解密能力,完全符合裝置叢集的最小權限模型。

kms:ReEncrypt — 在不暴露明文的情況下輪換密文

kms:ReEncrypt 接受以某個 AWS KMS 金鑰加密的密文,並以第二個 AWS KMS 金鑰(或相同金鑰搭配不同的加密上下文)重新加密它——明文始終不離開 AWS KMS。這個 API 用於安全事件後將加密資料輪換至新金鑰、從 AWS 受管金鑰遷移至客戶受管金鑰,或將密文複製至使用不同金鑰的新 AWS 區域。呼叫方需要對來源金鑰具備 kms:ReEncryptFrom 權限,對目的地金鑰具備 kms:ReEncryptTo 權限。

在 DVA-C02 中,對 1 MB 檔案、10 MB Amazon S3 物件或 100 MB 備份檔案提議呼叫 kms:Encrypt 的答案選項都是錯的。kms:Encrypt 對任何超過 4,096 位元組的資料都會以 ValidationException 拒絕。正確模式是使用 kms:GenerateDataKey 進行信封加密:取得資料金鑰、在本地以 AES-256-GCM 加密大型酬載、將加密後的資料金鑰與密文一同儲存。參考:https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html

SDK 程式碼中的信封加密模式

信封加密是開發者程式碼中最常見的 AWS KMS 加密模式,DVA-C02 要求考生對其逐步流程相當熟悉。

五步驟流程

  1. 索取新的資料金鑰。 呼叫 kms:GenerateDataKeyKeyId 設為你的 AWS KMS 金鑰 ARN 或別名,KeySpec: AES_256,並帶入可識別被保護邏輯物件的 EncryptionContext(例如 { TenantId, DocumentId })。
  2. 在本地加密。Plaintext 資料金鑰搭配你偏好語言的 AES-256-GCM 本地實作(Node.js crypto、Python cryptography、Java Cipher、Go crypto/cipher)進行加密。
  3. 持久化密文與中繼資料。 將 AES-GCM 密文、12 位元組 IV、16 位元組驗證標籤,以及 CiphertextBlob(加密後的資料金鑰)一同儲存。常見的儲存位置包含 Amazon S3 物件中繼資料、Amazon DynamoDB 的屬性欄位,或 Amazon Kinesis 記錄中的封裝結構。
  4. 清零明文。 以零覆寫 Plaintext 緩衝區並移除所有參考。有垃圾回收機制的語言無法保證這一點,但盡力清零可縮短明文存在於程序記憶體中的時間窗口。
  5. 解密時反向操作。 取出加密後的資料金鑰,以相同的加密上下文呼叫 kms:Decrypt,使用解包後的明文資料金鑰以 AES-256-GCM 解密酬載(並驗證驗證標籤),再次清零。

為何信封加密能擴展

單一的 GenerateDataKey 呼叫可保護 MB、GB 甚至 TB 等級的酬載。AWS KMS 每次呼叫只處理 32 位元組的金鑰材料,因此單一客戶受管 AWS KMS 金鑰可在不成為瓶頸的情況下,每秒為你的叢集服務數萬次酬載加密呼叫。AES-256-GCM 的大量加密在你自己的程序中進行,使用你本就在支付的 CPU 週期。

為何比每次呼叫 kms:Encrypt 更安全

對大型酬載的每個區塊分別呼叫 kms:Encrypt,會(1)將 AWS KMS 請求量與成本乘以區塊數量,(2)讓你因熱門物件而暴露於 AWS KMS 節流風險,以及(3)仍受每次呼叫 4 KB 的限制約束。信封加密同時解決了這三個問題。

  1. kms:GenerateDataKey{ Plaintext, CiphertextBlob }
  2. Plaintext 使用 AES-256-GCM 加密酬載。
  3. 將密文 + IV + tag + CiphertextBlob 一同儲存。
  4. 使用後立即清零 Plaintext
  5. 讀取時:kms:Decrypt(CiphertextBlob, EncryptionContext) → 明文資料金鑰 → AES-256-GCM 解密 → 清零。

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

加密上下文——綁定於密文的附加驗證資料(AAD)

加密上下文是 AWS KMS 加密中最與開發者相關的功能之一,也是 DVA-C02 常見的考題標的。

它是什麼

加密上下文是一個非機密的鍵值對映射(僅接受字串),你在任何 AWS KMS 加密、解密、產生資料金鑰或重新加密呼叫中傳遞它。AWS KMS 將它視為保護密文 blob 或資料金鑰的 AES-GCM 加密的附加驗證資料(AAD)。這意味著:

  • 加密上下文本身不是機密——它以明文記錄至 AWS CloudTrail,非常適合稽核「哪個租戶的哪份資料被誰解密」。
  • 解密時,呼叫方必須提供與加密時完全相同的加密上下文,否則 AWS KMS 回傳 InvalidCiphertextException
  • 加密上下文在密碼學層面與密文綁定——在租戶之間或在不同物件金鑰之間對調密文無效。

善用加密上下文的模式

  • 多租戶隔離{ TenantId: "acme-corp" }。若某個 bug 試圖在租戶 B 的請求路徑中解密租戶 A 的密文,AWS KMS 會直接拒絕。
  • 物件身份綁定{ BucketName: "invoices", ObjectKey: "2026/04/invoice-123.pdf" }。將密文移至不同的物件金鑰即使解密失效。
  • 用途綁定{ Purpose: "session-token" } vs { Purpose: "refresh-token" }。防止在不同情境間意外重用。

AWS 服務整合中的加密上下文

許多 AWS 服務會自動設定加密上下文:

  • AWS Lambda 環境變數使用 { "aws:lambda:FunctionName": "<function-name>" },因此即使具備相同 IAM 權限,不同函式也無法解密相同的環境變數。
  • Amazon S3 SSE-KMS 使用 { "aws:s3:arn": "arn:aws:s3:::bucket/key" }
  • AWS Secrets Manager 使用 { "SecretARN": ..., "SecretVersionId": ... }

你可以在 AWS CloudTrail 的 Decrypt 事件中觀察這些內容,這也是 DVA-C02 中偵錯「為何這次 Decrypt 成功或失敗」的標準做法。

經典的 DVA-C02 陷阱:情境以 { TenantId: "Acme" } 加密,卻以 { tenantId: "Acme" } 解密(鍵名首字母小寫)。呼叫以 InvalidCiphertextException 失敗。加密上下文的鍵值對區分大小寫,解密時必須完全相符。鍵的順序無關緊要,但拼寫與大小寫至關重要。參考:https://docs.aws.amazon.com/kms/latest/developerguide/encrypt_context.html

AWS SDK 中的 AWS KMS——代你完成工作的服務整合

大多數應用程式程式碼從不直接呼叫 GenerateDataKey。開發者只需將 AWS KMS 參數傳入 AWS 服務的 SDK 呼叫,由服務在底層自行執行信封加密。

Amazon S3 — 透過 PutObject 選擇 SSE-S3、SSE-KMS、SSE-C 或 DSSE-KMS

PutObject 時,開發者透過 SDK 參數選擇伺服器端加密方式:

// SSE-S3(由 S3 完全管理的 AES-256,自 2023 年 1 月起為預設值)
await s3.send(new PutObjectCommand({
  Bucket, Key, Body, ServerSideEncryption: "AES256"
}));

// SSE-KMS,指定 AWS KMS 金鑰與加密上下文
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 — 兩層獨立的伺服器端加密
await s3.send(new PutObjectCommand({
  Bucket, Key, Body,
  ServerSideEncryption: "aws:kms:dsse",
  SSEKMSKeyId: "alias/customer-data"
}));

// SSE-C — 每次請求都提供客戶自備的金鑰位元組
await s3.send(new PutObjectCommand({
  Bucket, Key, Body,
  SSECustomerAlgorithm: "AES256",
  SSECustomerKey: customerKeyBytes,
  SSECustomerKeyMD5: md5OfCustomerKey
}));

使用 SSE-KMS 的 GetObject 無需任何特殊處理——Amazon S3 會代你呼叫 kms:Decrypt,使用呼叫方的 IAM 主體,該主體必須透過 IAM 政策或 AWS KMS 金鑰政策的 IAM 委派,對 AWS KMS 金鑰具備 kms:Decrypt 權限。

BucketKeyEnabled: true 是一個與開發者相關的最佳化:Amazon S3 快取短暫的儲存貯體層級中間金鑰,將 AWS KMS 請求量降低約 99%,在維持 AWS CloudTrail 稽核記錄的同時,防止熱門儲存貯體發生節流。

Amazon DynamoDB — 靜態加密始終開啟

Amazon DynamoDB 資料表永遠處於靜態加密狀態。開發者只需選擇金鑰:

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

預設使用 AWS 自有金鑰(免費,無 CloudTrail 稽核)。指定 SSEType: "KMS" 搭配別名,可指向 aws/dynamodb(AWS 受管)或客戶受管金鑰。若需對 item 內的欄位進行欄位層級加密,請使用 Amazon DynamoDB Encryption Client(見下文)。

Amazon SQS 與 Amazon SNS — 佇列或主題上的 SSE-KMS

Amazon SQS 與 Amazon SNS 都支援以 AWS KMS 金鑰進行 SSE。在 SDK 中,你在建立佇列或主題時設定 KmsMasterKeyId 屬性,服務即會為每則訊息處理信封加密。加密上下文包含佇列或主題的 ARN。

AWS Lambda 環境變數加密

Lambda 環境變數預設以 AWS 受管 AWS KMS 金鑰(aws/lambda)靜態加密。若需在預設之外提供額外保護,請在 Lambda 主控台或透過 SDK 啟用**「傳輸中加密輔助工具」**選項,該選項會以客戶受管 AWS KMS 金鑰對環境變數值進行第二次加密,並要求你的函式程式碼在冷啟動時明確解密:

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")

加密上下文 { LambdaFunctionName: ... } 是必填的,且必須符合函式名稱,這意味著將環境變數複製貼上到不同函式後無法解密——這是一個實用的跨函式隔離特性。

Amazon CloudWatch Logs 加密

Log group 可透過 AssociateKmsKey 以客戶受管 AWS KMS 金鑰加密:

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

AWS KMS 金鑰政策必須允許 logs.<region>.amazonaws.com 透過 kms:ViaService 條件使用金鑰,否則日誌寫入會無聲地失敗。

DVA-C02 的常見錯誤是試圖在 PutObject 之前先呼叫 kms:Encrypt 加密 Amazon S3 物件。這有兩個問題:(1)只對 4 KB 以下的物件有效,(2)當你傳入 ServerSideEncryption: "aws:kms"SSEKMSKeyId 時,Amazon S3 已經自行處理信封加密。正確模式是讓服務來做——在服務 SDK 呼叫(PutObjectPutMessagePutRecord)上傳遞 AWS KMS 參數,Amazon S3、Amazon SQS 或 Amazon Kinesis 會代你呼叫 AWS KMS。參考:https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html

用戶端加密——AWS Encryption SDK 與 DynamoDB Encryption Client

對於必須在資料離開應用程式程序之前就完成加密(讓 AWS 服務從未看到明文)的工作負載,AWS 提供了兩個官方用戶端函式庫。

AWS Encryption SDK

AWS Encryption SDK 是一個通用的用戶端加密函式庫,支援 Java、Python、C、JavaScript 與 .NET。它將 AWS KMS 信封加密封裝在簡單的 encryptdecrypt 介面背後,處理加密後資料金鑰與中繼資料的可攜式密文格式序列化,並支援進階功能,如多重封裝金鑰(用於跨區域或多方解密)、金鑰承諾(防禦解密 oracle 攻擊),以及資料金鑰快取(提升吞吐量)。

最簡化的 Python 範例:

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"}
)

用戶端加密意味著 Amazon S3、Amazon DynamoDB 或任何其他目的地只會看到不透明的密文——即使是遭入侵的 AWS 操作人員也無法讀取原始位元組。

Amazon DynamoDB Encryption Client

Amazon DynamoDB Encryption Client(現為 AWS Database Encryption SDK 的一部分)在 PutItem 前與 GetItem 後,對 Amazon DynamoDB item 執行逐屬性的欄位層級加密與簽章。你聲明哪些屬性要加密、哪些只簽署不加密(以便仍可用於查詢)、哪些維持明文。函式庫從 AWS KMS 取得資料金鑰並處理信封模式,產生一個完全由用戶端加密的 item,Amazon DynamoDB 儲存時從未看到敏感欄位。

典型的屬性分類:

  • ENCRYPT_AND_SIGN — 敏感數值(身分證字號、信用卡號)。
  • SIGN_ONLY — 必須維持明文以供查詢但不可被竄改的查詢鍵。
  • DO_NOTHING — 完全公開的數值。

何時選擇用戶端加密而非伺服器端加密

在以下情況選擇用戶端加密:威脅模型不信任 AWS 服務本身、法規禁止 AWS 在任何情況下存取明文,或資料必須在不同層級重新加密(例如行動用戶端到服務的端對端加密)。在以下情況選擇伺服器端加密(SSE-KMS、DSSE-KMS、DynamoDB 靜態加密):你只需要靜態保護,且信任 AWS 服務的信封加密能處理一切。

KMS Grants — 委派的窄範圍許可

Grants 是 AWS KMS 加密的一個功能,專門為程式化、臨時性的許可委派而設計。在 DVA-C02 中,它們出現在涉及掛載磁碟區、短暫任務與跨主體工作流程的情境中。

Grant 是什麼

Grant 是 AWS KMS 金鑰上的一份許可文件,它:

  • 允許特定的被授予主體(IAM 角色、使用者或 AWS 服務)執行特定的 AWS KMS 操作(DecryptEncryptGenerateDataKeyReEncryptFromReEncryptTo 等)。
  • 受到特定的 grant 限制條件約束——最重要的是 EncryptionContextEqualsEncryptionContextSubset,將 grant 綁定至以符合的加密上下文執行的操作。
  • 可隨時由授予方、被授予方(若被允許)或 grant 的退休主體撤銷或退休。
  • 在幾分鐘內生效(最終一致性),並在 AWS CloudTrail 中留有紀錄。

為何使用 Grant 而非編輯金鑰政策

金鑰政策是長期存在、全域範圍的,且需要 kms:PutKeyPolicy 權限(通常只有資安管理員才有)。Grants 則具有以下特性:

  • 臨時性:可由應用程式程式碼或 AWS 服務建立和退休。
  • 窄範圍:限制於特定的加密上下文與特定的被授予方。
  • 非阻塞性:不需編輯主要金鑰政策,降低變更管理的摩擦。

常見的 Grant 使用模式

  • Amazon EBS 掛載至 Amazon EC2:Amazon EBS 在 AWS KMS 金鑰上建立一個 grant,精確限定在正在掛載的磁碟區;該 grant 只允許對那顆磁碟區執行 kms:Decryptkms:GenerateDataKeyWithoutPlaintext
  • AWS Lambda@Edge 需要跨區域解密:在每個邊緣區域的多區域金鑰副本上建立 grant,範圍限定至 Lambda 執行角色。
  • Amazon EMR 讀取加密的 Amazon S3 資料:建立允許 EMR 叢集角色只解密具有相符加密上下文之物件的 grant。

如果你發現自己每次有新的 AWS Lambda 函式或容器任務需要臨時存取時,就想要編輯 AWS KMS 金鑰政策,你可能需要的是 grant。Grants 的設計就是要由程式碼發出和退休。它們會出現在 kms:CreateGrant CloudTrail 事件中,稽核記錄完整保留。參考:https://docs.aws.amazon.com/kms/latest/developerguide/grants.html

非對稱 AWS KMS 金鑰——Sign、Verify、Encrypt、Decrypt

非對稱 AWS KMS 金鑰是 RSA 或 ECC 金鑰對,其中公鑰可以匯出並發佈,但私鑰永遠留在 AWS KMS 內部。

kms:Signkms:Verify

數位簽章的用法:

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

// 之後,任何持有公鑰的地方:
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

典型使用案例:簽署 JWT、簽署軟體成品、簽署稽核記錄以防竄改、簽署憑證請求、AWS Lambda 的程式碼簽署。

kms:GetPublicKey 進行離線驗證

對於不應在每次呼叫都觸及 AWS KMS 的高流量驗證路徑,以 kms:GetPublicKey 取得一次公鑰,再使用任何標準加密函式庫在本地驗章。私鑰永不離開 AWS KMS;只有公開那一半被發佈出去。

非對稱加密/解密

非對稱 AWS KMS 金鑰也可以搭配 RSAES_OAEP_SHA_256 進行 kms:Encryptkms:Decrypt。常見模式:只持有公鑰的發送方加密一個小型酬載(仍有 4 KB 上限),只有私鑰持有者——AWS KMS——才能解密。適用於不應具備解密授權的系統進行單向機密注入。

非對稱金鑰輪換是手動的

與對稱 AWS KMS 金鑰不同,非對稱金鑰無法使用自動金鑰輪換。輪換時,你需要建立新的非對稱 AWS KMS 金鑰、更新別名指向新金鑰、將新公鑰重新發佈給驗章方,並保留舊金鑰足夠長的時間以讓所有既有簽章完成驗章。

多區域金鑰——跨 AWS 區域共享相同金鑰 ID

多區域金鑰是 AWS KMS 加密的一個功能,直接面向全球分散式應用程式的開發者。

多區域金鑰解決了什麼問題

在單一區域的設計中,在 us-east-1 加密的密文無法在 eu-west-1 解密,除非發起跨區域的 AWS KMS 呼叫,這會引入延遲、成本與跨區域故障相依性。多區域金鑰是一組相關的 AWS KMS 金鑰——一個主要金鑰與一或多個副本——共享相同的金鑰 ID 與相同的底層金鑰材料,但分佈在不同的 AWS 區域。以某個副本加密的密文可由任何其他副本解密,無需任何跨區域 AWS KMS 呼叫。

如何建立與使用

// 在 us-east-1 建立主要金鑰
const primary = await kms.send(new CreateKeyCommand({
  MultiRegion: true,
  KeyUsage: "ENCRYPT_DECRYPT"
}));

// 複製至 eu-west-1(在該區域使用獨立的 AWS KMS 用戶端)
await kmsEu.send(new ReplicateKeyCommand({
  KeyId: primary.KeyMetadata.KeyId,
  ReplicaRegion: "eu-west-1"
}));

所有副本共享金鑰 ID(後綴部分,而非 ARN);其 ARN 因區域而異。在 us-east-1 產生的密文包含中繼資料,讓任何副本都能解密——你的程式碼只需在 Decrypt 時呼叫本地副本的 ARN。

何時使用

  • Amazon DynamoDB Global Tables 搭配客戶受管金鑰加密——每個區域的副本使用其本地的多區域金鑰副本,因此跨區域容錯移轉時不需要跨區域的 AWS KMS 呼叫。
  • Amazon S3 跨區域複製搭配 SSE-KMS——來源儲存貯體與目的地儲存貯體各自使用其本地副本。
  • 主動-主動應用程式,相同密文必須同時在多個區域可讀。

多區域金鑰並非自動的跨區域金鑰共享。每個副本都是獨立的 AWS KMS 金鑰,擁有自己的金鑰政策、自己的 grants、自己的 CloudTrail 記錄,以及每月 $1 美元的費用。它們只是恰好共享金鑰材料。

AWS KMS 請求配額——開發者必須規劃的共享節流

AWS KMS 針對每區域、每帳號的 API 請求速率設有限制,這些限制在帳號內的所有 AWS 服務間共享,這是 DVA-C02 反覆出現的疑難排解情境。

配額一覽

以下是截至 2025 年,每區域、每帳號的對稱密碼學操作配額(近似值):

  • 大多數 AWS 區域的 EncryptDecryptGenerateDataKeyGenerateDataKeyWithoutPlaintextReEncrypt(共享配額)為每秒 10,000 個請求
  • 部分大型區域(us-east-1、us-west-2、eu-west-1)為每秒 30,000 個請求
  • 非對稱操作(SignVerifyGetPublicKey)、RSA 操作與 ECC 操作各有獨立配額,每秒上限較低。

為什麼「共享」很重要

那每秒 10,000 個請求是帳號內每個 AWS 服務共享的。Amazon S3 SSE-KMS 呼叫、Amazon DynamoDB 靜態金鑰查詢、AWS Lambda 環境變數在冷啟動時的解密、Amazon SQS 加密佇列的訊息寫入,以及你自己的應用程式呼叫——全都從同一個配額桶中扣除。一個頻繁存取的 Amazon S3 工作負載可能節流你的 Amazon DynamoDB 工作負載,反之亦然。

開發者可採取的緩解措施

  • 在每個 SSE-KMS 儲存貯體上啟用 Amazon S3 Bucket Keys——透過快取短暫的儲存貯體層級中間金鑰,將 AWS KMS 請求量減少約 99%。
  • 在應用程式程式碼中使用信封加密搭配長效資料金鑰(AWS Encryption SDK 資料金鑰快取)——單次 GenerateDataKey 呼叫可在資料金鑰輪換前保護數千個 item。
  • 對有慢性冷啟動問題的 AWS Lambda 函式使用 Provisioned Concurrency——減少冷啟動次數即減少解密次數。
  • 透過 AWS Service Quotas 申請增加配額,用於高吞吐量工作負載。
  • 將高流量工作負載分散至多個 AWS 區域——每個區域有自己的配額桶。

DVA-C02 情境有時描述「AWS KMS ThrottlingException 無預警出現;我們的程式碼沒有任何變更」。陷阱答案是怪罪應用程式。真正的原因通常是同帳號內的另一個工作負載(新增了使用 SSE-KMS 的 Amazon S3 儲存貯體、新加密的 AWS Lambda 環境變數,或正在載入加密 Amazon DynamoDB 資料的遷移作業)消耗了共享的每區域配額。啟用 Amazon S3 Bucket Keys 並申請增加配額。參考:https://docs.aws.amazon.com/kms/latest/developerguide/requests-per-second.html

AWS KMS 金鑰輪換——自動、手動與 ReEncrypt 模式

金鑰輪換既是 DVA-C02 的考試重點,也是開發者的責任。

對稱 AWS KMS 金鑰的自動金鑰輪換

對於使用 AWS 自有金鑰材料的客戶受管對稱 AWS KMS 金鑰,AWS KMS 預設每 365 天輪換一次底層密碼學材料(自 2024 年起可設定為 90 至 2,560 天)。金鑰 ID 與 ARN 不會改變,舊的金鑰材料被保留以確保既有加密資料仍可解密,且不需要修改任何應用程式程式碼。AWS 受管金鑰每年自動輪換;你無法停用此行為。

非對稱金鑰與匯入材料金鑰的手動輪換

非對稱金鑰與使用匯入(BYOK)金鑰材料的金鑰必須手動輪換:

  1. 建立新的 AWS KMS 金鑰。
  2. 更新別名(alias/app-v1 指向新金鑰)。
  3. 對必須受新金鑰材料保護的密文,呼叫 kms:ReEncrypt 進行重新封裝,過程中不暴露明文。

參考別名的應用程式無需重新部署即可繼續運作;硬編碼舊金鑰 ARN 的應用程式則需要設定變更。

ReEncrypt 的程式碼範例

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 是以新金鑰重新封裝的相同明文

呼叫方需要對來源金鑰具備 kms:ReEncryptFrom,對目的地金鑰具備 kms:ReEncryptTo。明文永不離開 AWS KMS。

  • 自動輪換:預設 365 天,可設定 90–2,560 天僅限使用 AWS 自有材料的對稱金鑰
  • 非對稱金鑰與匯入材料金鑰:僅支援手動輪換
  • 自動輪換後金鑰 ID 與 ARN 維持不變。
  • 舊金鑰材料被保留,既有加密資料仍可解密。
  • kms:ReEncrypt 在不暴露明文的情況下將密文重新封裝至新金鑰。
  • 參考:https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html

開發者考試陷阱——DVA-C02 上的 AWS KMS 加密

每次 DVA-C02 應考時,預計都會遇到以下幾個陷阱。

陷阱一:對大型酬載使用 kms:Encrypt

任何對 Amazon S3 物件、多 MB 檔案或串流酬載直接呼叫 kms:Encrypt 的答案都是錯的。4 KB 限制是絕對的。正確答案是以 kms:GenerateDataKey 進行信封加密。

陷阱二:解密時加密上下文遺漏或不符

若加密時使用了 { TenantId: "Acme" },解密時卻未帶入任何內容或帶入 { TenantId: "acme" },AWS KMS 回傳 InvalidCiphertextException。應用程式日誌通常顯示「密文不正確」,但真正的原因是上下文不符。

陷阱三:以為 IAM 本身就能授予 KMS 存取

AWS KMS 要求金鑰政策必須委派給 IAM,IAM 政策才能生效。若金鑰政策中沒有「啟用 IAM 政策」陳述式,IAM 中的 kms:Decrypt 會被忽略。DVA-C02 中「IAM 允許但呼叫失敗」的情境幾乎都是踩到這個點。

陷阱四:嘗試自動輪換非對稱金鑰

自動金鑰輪換僅適用於使用 AWS 自有材料的對稱金鑰。任何將「匯入金鑰材料」或「非對稱金鑰」與「啟用自動金鑰輪換」混在一起的情境,都是在指向錯誤答案——正確的工作流程是手動建立新金鑰 + 更新別名 + ReEncrypt。

陷阱五:忽略跨服務共享的 KMS 配額

工作負載在測試環境正常,在正式環境卻被節流,原因不是工作負載本身改變,而是同帳號內另一個 Amazon S3 儲存貯體或 Amazon DynamoDB 資料表開始消耗共享的每區域配額。啟用 Amazon S3 Bucket Keys、使用資料金鑰快取,並申請增加配額。

陷阱六:忘記 Lambda 環境變數的加密上下文

使用 Lambda 的加密輔助工具時,函式內的 kms:Decrypt 呼叫必須包含 EncryptionContext: { LambdaFunctionName: <function-name> }。忘記這一點會在冷啟動時回傳 InvalidCiphertextException,這也是 Lambda 面試中的經典問題。

陷阱七:跨區域程式碼沒有使用多區域金鑰

試圖在 eu-west-1 執行的服務中解密由 us-east-1 AWS KMS 金鑰產生的密文會失敗——KMS 呼叫必須發往擁有該金鑰的區域。解法是明確發起跨區域呼叫,或使用多區域金鑰讓每個區域擁有具相同材料的本地副本。

陷阱八:混淆 SSE-C 與用戶端加密

SSE-C(Amazon S3 上的 SSECustomerKey)仍是伺服器端加密——Amazon S3 短暫持有金鑰並看到明文以執行 AES-256,之後才丟棄金鑰。真正的用戶端加密使用 AWS Encryption SDK,Amazon S3 從未看到明文。DVA-C02 的干擾選項有時將兩者混為一談;它們並不相同。

AWS KMS 加密關鍵數字與必記事實

  • kms:Encrypt 明文限制:4,096 位元組(4 KB)
  • kms:GenerateDataKey 在單一回應中同時回傳明文與密文資料金鑰。
  • kms:GenerateDataKeyWithoutPlaintext 只回傳密文——供僅加密的生產者使用。
  • kms:ReEncrypt不暴露明文的情況下將密文重新封裝至新金鑰。
  • 加密上下文在解密時必須逐位元組相符(鍵與值均區分大小寫)。
  • AWS KMS 客戶受管金鑰費用:每金鑰每月 USD 1.00 + 每次請求費用。
  • 自動金鑰輪換預設:365 天,可設定 90–2,560 天,僅限 AWS 自有材料對稱金鑰。
  • 每區域共享配額:大多數區域約 ~10,000 req/s,大型區域約 ~30,000 req/s
  • Amazon S3 Bucket Keys 將 AWS KMS 請求量減少約 ~99%
  • 多區域金鑰跨區域共享金鑰 ID 與金鑰材料;每個副本每月收費 $1。
  • Lambda 環境變數加密上下文:{ LambdaFunctionName: <name> }
  • 金鑰刪除等待期:7 至 30 天
  • 參考:https://docs.aws.amazon.com/kms/latest/developerguide/overview.html

練習情境——DVA-C02 對應答案

  • 「上傳前先在本地加密一個 50 MB 影片檔至 Amazon S3,讓 Amazon S3 從未看到明文。」→ AWS Encryption SDK 用戶端加密,搭配客戶受管 AWS KMS 金鑰。
  • 「在儲存至 Amazon DynamoDB 前加密一個 200 位元組的 API 金鑰。」→ 直接呼叫 kms:Encrypt(未超過 4 KB),搭配加密上下文 { TenantId, Purpose }
  • 「在安全事件後,不在應用程式記憶體中暴露明文的情況下,將密文輪換至新的客戶受管金鑰。」→ kms:ReEncrypt,從舊金鑰指向新金鑰。
  • 「確保 AWS Lambda 環境變數的解密只在該特定函式內有效。」→ 啟用加密輔助工具,以 EncryptionContext: { LambdaFunctionName: $AWS_LAMBDA_FUNCTION_NAME } 解密。
  • 「允許 Amazon ECS 任務在處理特定 Amazon SQS 訊息期間使用 AWS KMS 金鑰解密。」→ KMS Grant,範圍限定至任務角色並設定 EncryptionContextEquals
  • 「Amazon S3 SSE-KMS 儲存貯體在每秒 8,000 個請求時被節流。」→ 在儲存貯體上啟用 Amazon S3 Bucket Keys
  • 「以永不離開 AWS 的私鑰簽署 JWT。」→ 非對稱 AWS KMS 金鑰,搭配 kms:Sign 使用 RSASSA_PSS_SHA_256
  • 「在 us-east-1eu-west-1 解密相同密文而不發起跨區域呼叫。」→ 多區域金鑰,在每個區域部署一個副本。
  • 「IoT 裝置必須加密遙測資料,但絕不能解密任何東西。」→ 每台裝置使用 kms:GenerateDataKeyWithoutPlaintext,以回傳的密文 blob 作為封裝後的資料金鑰。
  • 「對 Amazon DynamoDB item 中的身分證字號進行欄位層級加密,但 CustomerId 必須仍可查詢。」→ Amazon DynamoDB Encryption Client,對身分證字號使用 ENCRYPT_AND_SIGN,對 CustomerId 使用 SIGN_ONLY

FAQ — DVA-C02 AWS KMS 加密常見問題

Q1:為什麼 kms:Encrypt 對 100 KB 的檔案失敗?我應該改用什麼?

kms:Encrypt4,096 位元組(4 KB)的明文硬性限制;任何超過此限制的資料在密碼學操作執行之前就會以 ValidationException 被拒絕。針對較大酬載的正確模式是使用 kms:GenerateDataKey 進行信封加密:向 AWS KMS 索取新的 AES-256 資料金鑰,以回傳的明文資料金鑰在本地用 AES-256-GCM 加密酬載,將回傳的加密後資料金鑰與密文一同持久化儲存,並從記憶體中清零明文資料金鑰。解密時,對加密後的資料金鑰呼叫 kms:Decrypt 解包,在本地解密酬載。此模式讓 AWS KMS 加密得以擴展至 GB 等級的酬載,而 AWS KMS 每次呼叫只需處理 32 位元組。

Q2:什麼是加密上下文?為什麼每個 AWS KMS 加密範例都包含它?

加密上下文是一個非機密的鍵值對映射,在每次 AWS KMS 加密、解密、產生資料金鑰與重新加密呼叫中傳遞。AWS KMS 將它視為保護密文 blob 的 AES-GCM 加密的附加驗證資料(AAD),因此解密時必須提供相同的上下文,否則呼叫以 InvalidCiphertextException 失敗。它為開發者提供三項重要功能:(1)租戶或物件綁定——租戶 A 的密文無法因程式碼 bug 誤觸租戶 B 的路徑而被解密;(2)稽核——上下文以明文記錄至 AWS CloudTrail,你可以查詢「過去 24 小時內誰解密了 TenantId=Acme 的密文?」;(3)縱深防禦——IAM 可以允許 kms:Decrypt 呼叫,但若有 bug 導致租戶對調,仍會在密碼學層面失敗。

Q3:如何在不失去既有密文存取的情況下輪換 AWS KMS 金鑰的材料?

對於使用 AWS 自有材料的客戶受管對稱 AWS KMS 金鑰,啟用自動金鑰輪換——AWS KMS 每 365 天(或可設定的 90–2,560 天)產生新材料,金鑰 ID 與 ARN 不會改變,舊材料被保留以確保既有密文仍可解密,且不需要任何應用程式程式碼變更。對於非對稱金鑰或使用匯入 BYOK 材料的金鑰,輪換是手動的:建立新的 AWS KMS 金鑰,更新別名指向新金鑰,對必須以新材料重新封裝的密文呼叫 kms:ReEncrypt——過程中明文永不離開 AWS KMS。保留舊金鑰啟用狀態,直到所有既有密文都已重新加密或退役為止。

Q4:Amazon S3 上的 SSE-KMS 與 AWS Encryption SDK 的用戶端加密有何差異?

SSE-KMS 是伺服器端加密——你的 SDK 呼叫透過 TLS 將明文傳送給 Amazon S3,Amazon S3 代你呼叫 kms:GenerateDataKey,以資料金鑰加密物件並儲存密文。Amazon S3 在自身的服務邊界內短暫處理明文。你可以從 AWS CloudTrail 取得每次解密的記錄並進行精細的金鑰政策控制,並需支付 S3 與 AWS KMS 的請求費用。使用 AWS Encryption SDK 的用戶端加密在物件離開你的主機之前,就在你的應用程式程序內完成加密;Amazon S3 只儲存密文,即使在自身邊界內也從未看到明文。大多數靜態保護情境選擇 SSE-KMS,因為它更簡單且與所有 AWS 服務整合。當法規或威脅模型要求 AWS 在任何情況下都不能讀取明文,或需要從行動用戶端穿過 Amazon S3 到下游消費者的端對端加密時,選擇用戶端加密。

Q5:為什麼我的應用程式突然遇到 AWS KMS ThrottlingException,即使我自己的請求速率沒有改變?

AWS KMS 強制執行每區域、每帳號的請求配額,這些配額在帳號內的每個 AWS 服務間共享——Amazon S3 SSE-KMS 呼叫、Amazon DynamoDB 靜態金鑰查詢、AWS Lambda 環境變數解密、Amazon SQS 加密佇列操作,以及你自己的應用程式呼叫,全都從同一個約每秒 10,000 個請求的配額桶中扣除(大型區域約 30,000)。新部署的 Amazon S3 工作負載、大型 Amazon DynamoDB 匯入,或一波 Lambda 冷啟動,都可能消耗配額並節流你原本穩定的應用程式。緩解措施:在每個 SSE-KMS 儲存貯體上啟用 Amazon S3 Bucket Keys(降低約 99% 的請求量)、在應用程式程式碼中使用 AWS Encryption SDK 資料金鑰快取以單一資料金鑰保護多個 item、為有慢性冷啟動問題的函式預留 Provisioned Concurrency、將高流量工作負載分散至多個 AWS 區域(每個區域有自己的配額),以及透過 AWS Service Quotas 申請增加配額。

Q6:如何讓某個 AWS Lambda 函式解密環境變數,同時防止相同密文被不同函式解密?

啟用 Lambda 的**「傳輸中加密輔助工具」**選項,該選項以客戶受管 AWS KMS 金鑰加密環境變數,並要求你的程式碼在冷啟動時解密。Lambda 自動將加密上下文設定為 { LambdaFunctionName: <function-name> },因此你的 kms:Decrypt 呼叫必須傳遞相同的 EncryptionContext: { LambdaFunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME }。若有人將密文複製至不同的 Lambda 函式,即使 IAM 角色恰好對同一個金鑰具備 kms:Decrypt 權限,解密也會以 InvalidCiphertextException 失敗,因為加密上下文中嵌入的函式名稱不符。搭配 AWS KMS 金鑰政策限制解密只能由特定函式的執行角色發起,可達到雙重隔離保障。

Q7:何時應使用 KMS Grant 而非編輯 AWS KMS 金鑰政策?

以下情況使用 Grant:臨時性、程式化、窄範圍的許可——例如 Amazon EBS 磁碟區掛載只需要針對該磁碟區的解密許可、Amazon ECS 任務只在處理特定批次時需要解密,或跨服務整合需要短期委派存取。Grants 由程式碼或 AWS 服務透過 kms:CreateGrantkms:RetireGrant 發出和退休,支援加密上下文限制條件將其綁定至特定操作,且不需要編輯主要金鑰政策(後者通常需要只有資安管理員才有的 kms:PutKeyPolicy 權限),並出現在 AWS CloudTrail 供稽核。以下情況使用金鑰政策:長期存在、帳號範圍的信任關係——例如將所有 IAM 授權委派給帳號的 IAM 政策,或授予特定正式環境角色永久的解密存取。Grants 是開發者工具;金鑰政策是平台治理工具。

Q8:多區域金鑰能做到跨區域 KMS 呼叫做不到的什麼?

多區域金鑰是一組相關的 AWS KMS 金鑰——一個主要金鑰與一或多個副本——跨 AWS 區域共享相同的金鑰 ID 與相同的底層金鑰材料。在某個區域產生的密文可由任何其他區域的副本解密,無需任何跨區域 AWS KMS 呼叫,消除了跨區域延遲並移除跨區域故障相依性。這對於使用客戶受管金鑰加密的 Amazon DynamoDB Global Tables、使用 SSE-KMS 的 Amazon S3 跨區域複製,以及相同密文必須同時在多個區域可讀的主動-主動應用程式,都至關重要。沒有多區域金鑰時,跨區域 KMS 呼叫仍然有效,但遠端區域的每次解密都會產生來回的延遲,且若主要區域或網路路徑中斷就會失敗——這正是多區域金鑰消除的單點故障。每個副本仍是擁有自己的金鑰政策、自己的 grants 與每月 $1 定價的獨立金鑰。

延伸閱讀

官方資料來源

更多 DVA-C02 主題