AWS KMS 基础:密钥管理服务原理与操作
AWS KMS,全称是 Key Management Service。说白了,它就是 AWS 帮你管加密密钥的一个托管服务。我自己第一次接触时,以为就是个加密机,后来发现它远不止这么简单。它背后是经过 FIPS 140-2 Level 3 认证的 HSM 集群,密钥永远不会以明文形式离开那个边界。
核心概念:CMK 与密钥层级
KMS 里最核心的东西叫 CMK(Customer Master Key),也就是客户主密钥。CMK 又分三种:
- AWS 托管 CMK——服务帮你创建、自动轮换,你不能碰。比如 S3 的 SSE-KMS 默认密钥。
- 客户托管 CMK——你创建、你控制轮换策略,可以启用/禁用。我建议生产环境都用这种。
- 外部导入 CMK——密钥材料来自你自己的 HSM 或本地系统。KMS 只保存加密后的副本。
每种 CMK 都有唯一标识符,格式是 arn:aws:kms:region:account-id:key/key-id。我记得第一次配置跨账号加密时,被这个 ARN 折腾了半天,最后发现密钥策略里必须显式授权外部账号使用 kms:Decrypt。
| 类型 | 自动轮换 | 可删除/禁用 | 密钥材料来源 |
|---|---|---|---|
| AWS 托管 CMK | 是(每年一次) | 否(仅可禁用关联服务) | AWS 内部 |
| 客户托管 CMK | 可选(每年一次) | 是 | AWS 内部 |
| 外部导入 CMK | 否(需手动重新导入) | 是 | 您自己控制 |
密钥存储与 HSM
CMK 存储在 KMS 的后端 HSM 集群里。每个 HSM 都是一台专用加密硬件,固件经过严格审计。KMS 本身不暴露 HSM 的原始接口,你只能通过 KMS API 间接操作。说白了,AWS 帮你承担了硬件安全模块的运维压力,你只要付 API 调用费就行。
嗯,这里要注意:KMS 并不存储你的加密数据,它只存储密钥和加密后的密钥材料。每个 CMK 在哪个区域创建,就固定在该区域的 HSM 里,不能跨区域复制——但你可以跨区域调用 API。
基本操作:加密、解密、重新加密
最常用的 API 是 Encrypt 和 Decrypt。你传一段明文(最多 64KB),得到密文。解密时传密文,拿回原文。KMS 的 Decrypt 会自动判断该用哪个 CMK,只要你有权限。
# 加密
aws kms encrypt \
--key-id alias/my-key \
--plaintext fileb://secret.txt \
--output text \
--query CiphertextBlob | base64 --decode > secret.enc
# 解密
aws kms decrypt \
--ciphertext-blob fileb://secret.enc \
--output text \
--query Plaintext | base64 --decode > secret-dec.txt
大文件怎么办?KMS 支持 信封加密。你先用 KMS 生成一个数据密钥(Data Key),然后用数据密钥加密你的大文件,最后用 KMS 加密数据密钥本身。这样你只产生一次 KMS 调用成本,却可以加密 GB 级别的数据。
权限控制:密钥策略 vs IAM 策略
这是最容易踩坑的地方。KMS 有两层授权体系:
- 密钥策略——直接写在 CMK 上的资源策略,控制谁可以对该密钥进行哪些操作。跨账号访问必须用密钥策略。
- IAM 策略——附加到 IAM 用户/角色的普通策略。如果密钥策略允许 IAM 委托权限,那么 IAM 策略就能生效。
我曾经花了两小时排查一个解密失败问题:用户的 IAM 策略里写了 kms:Decrypt,但密钥策略拒绝非 VPC 流量。结果所有来自公网的解密请求都被拦下。解决问题不是加 IAM 权限,而是在密钥策略里加上 VPC 条件。
自动密钥轮换
客户托管 CMK 支持自动轮换,默认关闭。开启后,KMS 每年生成一个新的密钥版本(Backing Key),原来的密钥版本继续存在,用于解密旧数据。新数据会使用最新版本加密。注意,轮换不改变 CMK 的 ARN,你的代码不用改。
但外部导入 CMK 不支持自动轮换。你需要自己创建一个新的 CMK,手动导入新密钥材料,然后更新引用。我建议这种场景下写一个自动化脚本,配合 Lambda 定期运行。
KMS 的典型应用场景
- S3 加密:配合 SSE-KMS,对象在写 S3 时自动用 CMK 加密。
- RDS 加密:创建 RDS 实例时选择 KMS 加密,数据文件自动加密。
- Lambda 环境变量:用 KMS 加密敏感配置,代码运行时解密。
- 日志加密:CloudTrail 或 S3 访问日志启用 KMS 加密。
核心流程关系图
避坑清单(实战笔记)
做 KMS 项目这些年,我整理了几个容易翻车的地方,供你参考:
- 跨区域调用默认不工作:CMK 是区域资源。要解密必须使用创建密钥的同一个区域。如果你的应用是多区域部署,每个区域需要独立创建 CMK。
- 密钥删除有等待期:执行
ScheduleKeyDeletion后,默认有 7-30 天的等待期。期间可以取消删除。千万别手快直接删——我就干过一次,把测试环境的密钥排除了,结果写死的加密数据全废了。 - 别名(Alias)不是安全的资源:别名只是一个指针,指向 CMK。如果你删除了原始 CMK 再创建一个同名的,别名会自动指向新 CMK。所以
alias/my-key可能表面不换实则密钥换了,旧密文将无法解密。我建议在关键策略里使用密钥 ID(Key ID)而不是别名。 - CloudTrail 日志默认不记录解密明文:KMS 的
Decrypt事件只记录请求参数和响应中的加密上下文,不会泄露明文。这一点在审计合规中很重要。
好,AWS KMS 的基础原理和操作就梳理到这儿。下一块内容会聚焦 KMS 的日志事件格式——尤其是 CloudTrail 里那些字段到底在记录什么。