密钥权限管理:基于IAM策略和密钥策略的访问控制

密钥权限管理,说白了就是回答一个问题:谁,能用哪把KMS密钥,干什么事?

AWS KMS里有两套并行的权限体系——IAM策略和密钥策略。为什么需要两套?嗯,这得从实际场景说起。我刚接手一个金融项目时,安全审计员要求“每个密钥只能被特定微服务访问”,但团队里好多人又需要解密测试环境的密钥。两套策略正好把全局授权和密钥级授权分开管理,灵活又安全。

两套策略的分工

  • IAM策略:挂载在IAM用户、组或角色上。你想想看,它就像一个“通行证”,告诉服务“这个角色能调用KMS的Decrypt、GenerateDataKey等API”。但IAM策略本身不会说“允许用哪把具体的密钥”,它只声明Resource: "*"或指定密钥ARN。
  • 密钥策略:直接写在KMS密钥上,像个“门禁”。它说:“哪些IAM身份能进我这扇门,进来后能做什么操作。” 密钥策略是资源型策略,只影响这一个密钥。

我记得刚学KMS时有个误区:以为只要IAM策略给了KMS权限,就能用所有密钥。错!密钥策略如果没放行,就算IAM管理员也甭想碰那把锁。

评估逻辑:我怎么判断你有权限?

访问KMS时,系统会把IAM策略和密钥策略做合并评估。流程是这样的:

  1. 检查调用者的IAM策略——显式拒绝优先,有拒绝直接返回AccessDenied。
  2. 通过IAM策略后,再查密钥策略——同样,显式拒绝优先。
  3. 两边的策略都得有允许语句(或用默认的“允许·所有账户管理员”兜底),才算授权通过。

注意:显式拒绝在任何策略中出现,都优先于任何允许。我曾经踩过坑:加了一条IAM条件“禁止生产环境以外的调用”,结果把预发环境的解密全拦了,排查半天才发现条件写得太宽。

KMS密钥访问控制决策流程 密钥访问控制评估流程 用户/角色请求 IAM策略评估 密钥策略评估 允许? ✅ 允许 ❌ 拒绝 显式拒绝→拒绝 两边都要 有 Allow 才放行

IAM策略示例:赋予EC2角色解密权限

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/mrk-1234abcd"
    }
  ]
}

这个策略挂给EC2实例角色后,实例就可以解密指定密钥的数据了。但注意,Resource必须填密钥ARN——我见过有人写成*,结果密钥策略没开,照样403。

密钥策略示例:允许跨账户访问

假设你想让另一个AWS账户的某IAM角色能用这把密钥:

{
  "Version": "2012-10-17",
  "Id": "key-policy-1",
  "Statement": [
    {
      "Sid": "Enable cross-account access",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/PartnerRole"
      },
      "Action": "kms:Decrypt",
      "Resource": "*"
    },
    {
      "Sid": "Allow administration of the key",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    }
  ]
}

注意:跨账户场景中,密钥策略是唯一能让外部主体访问的机制。IAM策略只作用在本账户的身份上。我在做多账户审计时,经常需要检查密钥策略里是否不小心暴露了敏感密钥给外部。

IAM策略 vs. 密钥策略:关键对比

维度IAM策略密钥策略
控制范围按身份(用户/角色/组)按资源(单个KMS密钥)
谁可以写有IAM权限的管理员拥有密钥管理权限的用户(可委托)
跨账户支持不支持(只能控制本账户身份)支持,直接指定外部Principal
默认行为隐式拒绝(无显式允许即拒绝)默认只允许根账户管理员访问
常见场景批量授权:比如给开发组所有成员解密权限细粒度控制:比如生产密钥只给特定微服务

避坑指南:策略冲突与调试

  • 不要同时依赖IAM和密钥策略的“默认允许”。密钥策略的默认行为只允许根账户,如果你删除了根账户而只留IAM允许,密钥策略会拦截掉所有请求。
  • 条件键(Conditions)要精确。比如kms:EncryptionContextKeys可以限制只能用特定的加密上下文。我曾经写过一个条件:StringEquals: kms:EncryptionContext:department = "finance",结果开发传了个department=Finance,大小写不匹配直接拒绝。
  • 理解“显式拒绝优先级”。即使IAM策略和密钥策略都允许,只要其中任何一个有显式拒绝,访问就被拒绝。你在密钥策略里写了拒绝某个IAM角色,那人就算在IAM里是管理员也进不去。

我个人习惯的做法是:密钥策略上只控制跨账户访问和基础管理权限;日常的服务调用权限统一交给IAM策略。这样密钥策略条目少,维护起来清晰。
举个例子:我管理的一个日志密钥,只允许日志写入角色的GenerateDataKey操作,其余所有操作通过IAM策略按环境隔离。审计的时候,一行密钥策略就能看清外部授权范围。

模拟测试:用IAM Policy Simulator验证

你可以在AWS控制台打开IAM Policy Simulator,输入你的IAM策略和密钥策略的JSON组合,模拟不同身份对密钥的调用。我记得有一次线上解密超时,模拟器告诉我密钥策略里没写kms:Decrypt给该角色,实际却是IAM策略先拒绝了——模拟器清晰展示了每一步的评估结果。省了不少debug时间。

总结一下:KMS的权限管理,核心就是理解“双策略联合评估”。IAM策略管谁有资格调用,密钥策略管密钥愿不愿意被调用。两者缺一不可。你想想看,如果只靠IAM,一旦密钥策略被意外修改,你会瞬间丢失所有访问;如果只靠密钥策略,那跨账户和批量授权就变成噩梦。两套体系互相补充,才是云上密钥安全的基石。