密钥权限管理:基于IAM策略和密钥策略的访问控制
密钥权限管理,说白了就是回答一个问题:谁,能用哪把KMS密钥,干什么事?
AWS KMS里有两套并行的权限体系——IAM策略和密钥策略。为什么需要两套?嗯,这得从实际场景说起。我刚接手一个金融项目时,安全审计员要求“每个密钥只能被特定微服务访问”,但团队里好多人又需要解密测试环境的密钥。两套策略正好把全局授权和密钥级授权分开管理,灵活又安全。
两套策略的分工
- IAM策略:挂载在IAM用户、组或角色上。你想想看,它就像一个“通行证”,告诉服务“这个角色能调用KMS的
Decrypt、GenerateDataKey等API”。但IAM策略本身不会说“允许用哪把具体的密钥”,它只声明Resource: "*"或指定密钥ARN。 - 密钥策略:直接写在KMS密钥上,像个“门禁”。它说:“哪些IAM身份能进我这扇门,进来后能做什么操作。” 密钥策略是资源型策略,只影响这一个密钥。
我记得刚学KMS时有个误区:以为只要IAM策略给了KMS权限,就能用所有密钥。错!密钥策略如果没放行,就算IAM管理员也甭想碰那把锁。
评估逻辑:我怎么判断你有权限?
访问KMS时,系统会把IAM策略和密钥策略做合并评估。流程是这样的:
- 检查调用者的IAM策略——显式拒绝优先,有拒绝直接返回
AccessDenied。 - 通过IAM策略后,再查密钥策略——同样,显式拒绝优先。
- 两边的策略都得有允许语句(或用默认的“允许·所有账户管理员”兜底),才算授权通过。
注意:显式拒绝在任何策略中出现,都优先于任何允许。我曾经踩过坑:加了一条IAM条件“禁止生产环境以外的调用”,结果把预发环境的解密全拦了,排查半天才发现条件写得太宽。
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策略按环境隔离。审计的时候,一行密钥策略就能看清外部授权范围。
举个例子:我管理的一个日志密钥,只允许日志写入角色的GenerateDataKey操作,其余所有操作通过IAM策略按环境隔离。审计的时候,一行密钥策略就能看清外部授权范围。
模拟测试:用IAM Policy Simulator验证
你可以在AWS控制台打开IAM Policy Simulator,输入你的IAM策略和密钥策略的JSON组合,模拟不同身份对密钥的调用。我记得有一次线上解密超时,模拟器告诉我密钥策略里没写kms:Decrypt给该角色,实际却是IAM策略先拒绝了——模拟器清晰展示了每一步的评估结果。省了不少debug时间。
总结一下:KMS的权限管理,核心就是理解“双策略联合评估”。IAM策略管谁有资格调用,密钥策略管密钥愿不愿意被调用。两者缺一不可。你想想看,如果只靠IAM,一旦密钥策略被意外修改,你会瞬间丢失所有访问;如果只靠密钥策略,那跨账户和批量授权就变成噩梦。两套体系互相补充,才是云上密钥安全的基石。