3、创建和管理KMS密钥(CMK)

这一章我们聊聊怎么创建和管理KMS里的客户主密钥。说白了,CMK是所有加密操作的根,它的命根子就是那个密钥材料。你把它管好了,整个加密体系就稳了一半。

我在项目里经常遇到的情况是:团队把密钥创建出来了,但后续的轮转、权限切割、生命周期管理基本没做。嗯,结果呢?一旦密钥泄露,整个加密体系就崩了。今天我把整个流程拆开来讲。

3.1 创建CMK的方式

在KMS里创建CMK,实际上有两种路径:

  • 通过KMS控制台创建的密钥 – AWS会自动帮你管理密钥材料的生命周期,包括自动轮转。适合大多数通用场景。
  • 通过AWS CloudHSM导入的自带密钥材料 – 密钥材料由你控制,KMS只做加解密操作。适合合规性要求特别高的环境,比如金融或者政府项目。

我个人习惯这么选:如果没什么特殊的外部合规约束,直接用AWS管理密钥材料的那一档;如果想保留密钥材料的控制权,那就选“导入自己的密钥材料”。但要注意,导入的密钥不支持自动轮转,你得自己去写脚本切换。

提个醒: 创建密钥时选的区域不能变。一旦定下来了,这个CMK只能在本地区域使用。跨区域加密需要使用别名或者新的CMK。

3.2 密钥策略非常重要

CMK本身只是加密工具,真正决定谁能用它的是密钥策略。嗯,这里要注意,密钥策略和IAM策略是两回事。IAM策略管的是“谁能在什么条件下调用KMS API”,而密钥策略管的是“这个CMK允许谁来做加解密操作”。两者必须同时生效。

我建议你在创建CMK的时候就把密钥策略写好。别等着后面再补,不然很容易出现“Permission denied”的玄学问题。

来看一个实际的密钥策略模板:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/MyAppRole"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "s3.ap-northeast-1.amazonaws.com"
        }
      }
    }
  ]
}

这个策略的意思是:只允许特定的IAM角色对S3服务进行加密和解密操作。其他调用,比如通过Lambda直接调用KMS,都会被拒绝。实践中,这种细粒度控制能大幅降低密钥滥用的风险。

3.3 密钥轮转的概念与实践

为什么要做密钥轮转?你想想看,密钥材料长期不换,一旦被暴力破解或者内部泄露,那损失是不可逆的。所以轮转是个基本动作。

AWS KMS提供两种轮转模式:

轮转类型 是否自动 轮转周期 对现有密钥的影响
自动轮转 是 每年一次 新增密钥材料,旧材料不删除,可用于解密旧数据
手动轮转 否 自定义(如每月、每季度) 需手动生成新密钥并更新引用,旧密钥可停用/删除

自动轮转的好处是不需要你操心,但只适用于AWS托管的密钥材料。如果你用的是导入的自带密钥材料,那就必须手动轮转。

警告: 我曾经在一个项目中看到,团队把旧密钥直接删掉了,结果用旧密钥加密的S3对象全部无法解密。所以千万记住:删除密钥之前,确认没有任何数据依赖这把密钥。建议在删除前设置一个“待删除周期”,默认是7天,这期间可以反悔恢复。

3.4 管理密钥的版本与生命周期

CMK不是只有一个密钥材料,它通常有多个版本来支持轮转。每个版本都有自己的密钥ID和状态。

KMS里常见的密钥状态:

  • 启用(Enabled) – 密钥可以正常用于加解密。
  • 禁用(Disabled) – 密钥被停止使用,加解密请求会失败。
  • 待删除(Pending Deletion) – 进入倒计时,期间可以取消删除。
  • 不可用(Unavailable) – 密钥材料已经过期或丢失,通常发生在导入密钥的场景。

我建议你养成定期审计的习惯,每季度至少检查一次CMK的状态。如果发现某些密钥长时间未被使用,可以考虑禁用或删除。但记住:禁用不等于删除,它还可以恢复。

3.5 使用标签和别名来管理密钥

随着密钥越来越多,光靠ARN来找密钥是很痛苦的。这时候标签和别名就能派上用场。

标签(Tag)可以给CMK打上环境、应用、业务线等维度信息。比如:

  • Environment=Production
  • Application=PaymentService
  • Owner=TeamAlpha

别名(Alias)则是一个可读的命名,比如 alias/payment-encryption-key。你可以在代码里直接引用别名,这样即便密钥轮转后底层的CMK变了,代码也不需要改动。

重点: 别名不能跨区域使用。在写代码或配置时,如果涉及跨区域加密,记得引用具体的CMK ARN,而不是别名。

3.6 生命周期管理流程图

下面是我整理的一个客户主密钥管理生命周期图,它把创建、使用、轮转、删除等关键节点串在一起了。

客户主密钥(CMK)管理生命周期 创建CMK 选择托管方式 设置密钥策略 权限控制 启用(Enabled) 开始加解密操作 密钥轮转 自动/手动 禁用或删除 确认无数据依赖 新版本 整个过程建议结合 CloudTrail 审计日志 删除前必须确保 无任何数据依赖此密钥

3.7 总结几个关键习惯

最后,我把这几年管密钥的经验浓缩成几条建议:

  1. 创建时就把策略写好 – 永远不要用默认策略,至少加上资源限制和条件。
  2. 打开自动轮转 – 如果用的是AWS托管密钥材料,这几乎是免费的安全升级。
  3. 打标准标签 – 方便后面用成本分配和安全审计。
  4. 审计日志开启 – KMS的每个API调用都会记录在CloudTrail里,这是排查问题的第一手资料。
  5. 禁用而非直接删除 – 除非你100%确定数据不再需要,否则先禁用观察一段时间。

嗯,这些习惯看着简单,但真能在生产环境里帮你省下大麻烦。我自己就因为在一套旧系统上没打标签,结果审计时根本分不清哪个密钥是哪个业务用的,最后只能全部重新梳理,折腾了两周。所以这些小动作,做在平时才不亏。