四、KMS 加密与解密原理归纳总结

好了,前面我们折腾了 IAM 角色和 KMS 的策略写法,是时候把最核心的加密解密原理捋一捋了。说实话,光会写策略不行,不明白底下数据流怎么跑的,出了错你都不知道从哪查起。

我个人习惯,讲原理一定得配图。咱们先看下面这张图,记住它的几个关键流转节点,后面就好理解了。

KMS 加密与解密核心数据流 加密流程(Encrypt) 应用程序 KMS 服务 GenerateDataKey 明文 DEK (本地) + 加密 DEK (CiphertextBlob) 返回 本地: 用明文 DEK 加密文件 → 密文文件 解密流程(Decrypt) 应用程序 KMS 服务 Decrypt(加密DEK) 返回明文DEK 本地: 明文 DEK 解密密文文件 → 原始文件 存储架构 S3 存两个东西:① 密文文件 ② 加密后的数据密钥 (CiphertextBlob) CMK 永远不出 KMS 服务区,DEK 用完即丢 关键原则 ① CMK 管理权限由 KMS Key Policy + IAM 双重控制 ② 调用方通过 KMS:Decrypt 权限控制是否能解密

4.1 KMS 里到底谁是真正的“钥匙”?

很多人一开始容易混淆,以为 KMS 是直接用 CMK 去加密你的文件。嗯,这里要注意,不是的。

我们把 KMS 的密钥分成三层来理解,你想想看:

  • CMK (Customer Master Key) —— 主公钥,永远待在 KMS 服务里,谁都没法导出。它只负责两件事:生成数据密钥、解密被它加密过的数据密钥。
  • DEK (Data Encryption Key) —— 数据密钥,这才是真正干活的。每次调用 GenerateDataKey,KMS 都会返回一份明文的 DEK(你的程序本地用)和一份被 CMK 加密后的 DEK(CiphertextBlob,存到存储里)。
  • 明文文件 —— 你的业务数据,用 DEK 加密后变成密文存入 S3 或本地。

我在项目中遇到过有人把 CMK 当 DEK 用,每次加密都调 Encrypt 传大文件,结果发现 KMS 限频了。其实没必要,KMS 设计就是为了管 CMK 的,干活的是 DEK。

4.2 加解密到底是怎么走的?

分两步走。咱们以最常见的“服务器端加密存储到 S3”场景为例。

加密阶段

  1. 应用程序(比如你的 Java 应用)调用 KMS GenerateDataKey,传入 CMK 的 ARN。
  2. KMS 验证你的 IAM 角色/用户是否有 kms:GenerateDataKey 权限,以及 CMK 的 Key Policy 是否允许。
  3. 权限通过,KMS 返回两份东西:
    明文 DEK(在你的内存里,用完记得清掉) + CiphertextBlob(加密后的 DEK,可以安全地存到任何地方)。
  4. 应用程序用明文 DEK 在本地加密你的数据文件,加密完后,直接把明文 DEK 丢掉(不要存盘!)。
  5. 把加密后的密文文件 + CiphertextBlob 一起上传到 S3。
💡 一个小技巧:有些人会把 CiphertextBlob 作为文件的自定义元数据一起存到 S3,这样解密的时候直接取出来就行,不用另外维护映射表。我个人觉得这样最方便。

解密阶段

  1. 应用从 S3 下载密文文件 + CiphertextBlob。
  2. 调用 KMS Decrypt,参数传 CiphertextBlob,不需要传 CMK ARN——因为 CiphertextBlob 里已经包含了 CMK 的引用信息。
  3. KMS 校验调用者的 kms:Decrypt 权限,以及 CMK 的策略。
  4. 权限通过,KMS 用 CMK 解密 CiphertextBlob,把明文 DEK 返回给你的程序。
  5. 程序用这个明文 DEK 解密密文文件,然后再次丢弃明文 DEK。
⚠️ 重点雷区:我曾经在排查一个问题时发现,某团队把 CiphertextBlob 弄丢了,结果所有数据都无法解密。CiphertextBlob 和密文文件必须一起保存,缺一不可。而且 CMK 一旦被禁用或删除,所有被它加密过的 CiphertextBlob 都会变成废纸。

4.3 权限检查的“双重门禁”

回到咱们课程的主题:IAM 与 KMS 策略。要成功调用 KMS 的加密解密 API,需要过两道门。

门禁层 控制实体 作用范围
第一道 IAM Policy(附加给角色/用户) 控制“谁有权限调用 KMS API”
第二道 KMS Key Policy + Grants 控制“该 CMK 允许谁来使用”

说白了,你 IAM 给了 kms:Decrypt 权限,但如果 CMK 的 Key Policy 里没把你这角色加进去,调用 Decrypt 照样返回 AccessDenied。反过来也一样。两边都得放行。

我建议你在刚开始搭建环境时,先用 AWS 管理控制台手动测试一下 CMK 的 Key Policy 配置,确认角色能过第二道门,再去改 IAM 策略。这样排查起来比较快。

4.4 数据密钥的缓存与重用

你可能想问:每次加密文件都去调 KMS 请求一次,会不会影响性能?

会。KMS 有 API 限流,默认每毫秒能调多少次看区域。所以最佳实践是:同一个 DEK 可以重复使用,只要你不觉得换密钥的频率太低。

举个例子,你生成一个 DEK,用它加密 1000 个小文件,然后把 CiphertextBlob 分别跟每个文件一起存。解密时,每个文件都拿同一个 CiphertextBlob 去调 Decrypt。因为 CMK 没变,解密结果是一样的。

核心要点总结

  • CMK 永远不出 KMS,只用来加密/解密 DEK。
  • DEK 是临时的,用完即弃,别存磁盘。
  • CiphertextBlob 是公开安全的,可以随文件一起存储。
  • 权限是 IAM + Key Policy 双保险,缺一不可。
  • DEK 可以缓存重用,但别把 CMK 当 DEK 用,会触发限频。

理解了这些,你再回头看那些策略配置,应该就清晰了。其实说白了,KMS 的核心设计思路就是:把密钥管理(CMK)和数据加密(DEK)分开,CMK 负责安全,DEK 负责效率。你只要保证 CMK 的权限控制不出漏洞,DEK 的生命周期管理不走样,整个加解密体系就是牢靠的。