4、密钥材料来源:KMS托管 vs 导入自有密钥材料(BYOK)

咱们直接切入正题。KMS 密钥的核心食材——密钥材料,就两个来源:一种让 AWS 帮你生,另一种你自己生然后灌进去。两种路子我都走过,今天把坑和心得一并倒出来。

4.1 两种模式的本质区别

说白了,KMS 托管密钥材料就是你告诉 KMS“给我造个密钥”,它背后会用 FIPS 140-2 Level 3 的 HSM 生成 Key Material,全程你碰不到原始字节。导入自有密钥材料(BYOK)呢?你自己拿本地 HSM、OpenSSL 甚至特殊固件生成密钥,然后通过 API 把它塞进 KMS 里。

我刚接触 BYOK 时觉得“既然 AWS 都帮我托管了,干嘛还要自己导入?”后来有个金融客户强制要求密钥材料必须在本地 HSM 生成,且要定期在本地验证完整性——嗯,BYOK 就是为了这类合规场景而生的。

对比维度 KMS 托管密钥材料 导入自有密钥材料(BYOK)
密钥生成地点 AWS HSM 内部 本地 HSM / 软件
原始材料是否可导出 否(完全由 AWS 控制) 否(导入后 KMS 也会加密存储,但本地可以保留副本)
密钥材料过期 不过期,永久有效 可设置过期时间,到期后自动删除
合规支持 满足大多数场景 满足本地密钥生成审计要求
运维复杂度 几乎为零 需要管理导入流程、过期策略
密钥材料是否可轮换 自动轮换,KMS 生成新版本 需手动创建新密钥并重新导入

你自己看表格就明白了。90% 的场景我用托管密钥材料——省心。但如果你遇到“密钥必须由我们公司自己的 HSM 生成”这种硬性合规要求,BYOK 就是唯一解。

4.2 导入自有密钥材料的完整流程

流程听起来复杂,实际操作起来我踩过两次坑,特别容易在“包裹密钥”那步翻车。我拆成 5 步:

  1. 创建 KMS 空密钥:CreateKey 时指定 Origin: EXTERNAL。注意,必须先创建再导入,不能反过来。
  2. 获取导入参数:调用 GetParametersForImport,拿到公钥和导入令牌。这公钥是 KMS 专为本次导入生成的 RSA 公钥,用于加密你的密钥材料。
  3. 在本地加密密钥材料:用拿到的公钥,对你的 256 位对称密钥(或非对称私钥)做 RSA-OAEP 加密。我记得第一次做这一步时,忘了指定正确的填充模式——OAEP with SHA-256,结果导进去 KMS 死活不认。
  4. 调用 ImportKeyMaterial:传入加密后的密文、导入令牌、可选过期时间。几分钟内密钥就变为“启用”状态。
  5. 验证:用密钥做一次简单的加解密测试,确认可用。

核心约束:导入的密钥材料必须是 256 位对称密钥,RSA OAEP 填充必须用 SHA-256。不支持 ECC 非对称密钥的 BYOK(除非用 CloudHSM 自定义 key store)。

下面是一段实际可用的 CLI 示例(以 Linux bash 为例):

# Step 1: 创建外部密钥
aws kms create-key --origin EXTERNAL

# Step 2: 获取导入参数(返回 KeyId, ImportToken, PublicKey)
aws kms get-parameters-for-import \
  --key-id 1234abcd-12ab-34cd-56ef-1234567890ab \
  --wrapping-algorithm RSAES_OAEP_SHA_256 \
  --wrapping-key-spec RSA_2048

# Step 3: 假设你的密钥材料在 plaintext.key(256位二进制)
openssl pkeyutl -encrypt \
  -inkey public_key.bin -pubin \
  -in plaintext.key \
  -out encrypted_key_material.bin \
  -pkeyopt rsa_padding_mode:oaep \
  -pkeyopt rsa_oaep_md:sha256

# Step 4: 导入
aws kms import-key-material \
  --key-id 1234abcd-12ab-34cd-56ef-1234567890ab \
  --import- fileb://ImportToken.bin \
  --encrypted-key-material fileb://encrypted_key_material.bin \
  --expiration-model KEY_MATERIAL_EXPIRES \
  --valid-to 2025-12-31T23:59:59Z

我的小技巧:encrypted_key_material.bin 一定要以二进制形式读取,别用 base64。CLI 的 fileb:// 前缀就是指示读二进制。

4.3 过期策略:KMS 托管 vs BYOK 的不同命运

KMS 托管的密钥材料永远不会过期。你只管开自动轮换,它会默默生成新版本。BYOK 呢?可以设过期时间,也可以设为“永不过期”。但我建议你设过期——为什么?因为一旦密钥材料泄露出本地,过期策略能强制废弃它。

我过去的一个项目吃过亏:BYOK 密钥没设过期,后来发现本地 HSM 的备份被人拷贝走了一份。虽然 KMS 内部的密文没事,但合规审计要求“立即废弃并更换”。因为没有过期时间,我们只能手动 DeleteKeyMaterial 再重新导入整个流程,搞得运维团队手忙脚乱。

从那以后,我对所有 BYOK 密钥都设 --expiration-model KEY_MATERIAL_EXPIRES 和明确的 --valid-to。这样审计安心,运维也自动淘汰旧材料。

⚠️ 注意:一旦密钥材料过期,KMS 会立即将密钥状态变为 PendingDeletion 吗?不,它直接变为 Disabled,且所有使用该密钥的加密操作都会失败。不存在“自动删除”,你需要手动清理或续期。所以要提前监控到期事件。

KMS密钥材料来源决策与流程 密钥材料来源决策与导入流程 选择密钥材料来源 KMS托管 BYOK CreateKey (Origin:AWS_KMS) 自动轮换 / 永不过期 CreateKey (Origin:EXTERNAL) GetParametersForImport 本地加密并ImportKeyMaterial 可设置过期 / 永不过期 ⚠️ 过期策略提醒 BYOK过期后密钥自动禁用 提前CloudWatch事件监控

4.4 何时选择 BYOK?三个真实案例

我不建议为了“技术炫酷”而用 BYOK。以下是我经历或观察过的正当理由:

  • 本地 HSM 合规要求:某金融客户必须使用经认证的本地 HSM 生成密钥,且保留生成日志。KMS 托管密钥无法提供“生成过程日志”给审计——BYOK 可以。
  • 密钥材料必须保留副本:你可以在本地安全存储一份加密后的密钥材料,等灾难恢复时再导入另一套 KMS 区域。托管密钥没有这份副本。
  • 长密钥轮换周期耦合本地政策:比如公司密钥政策要求“每年必须由安全团队亲手在离线 HSM 重生成一次”。KMS 自动轮换做不到“亲手”,只能用 BYOK 配合手动流程。

说到底,BYOK 不是偷懒的工具,它是给那些手握合规大棒、不得不“自产自销”的团队准备的。我的建议:能托管就别给自己加活,非要 BYOK 就严格做好过期策略和监控。