4. 权限不足导致轮换失败:IAM角色、ACL、云服务权限检查要点

密钥轮换失败,十次里有四五次都是权限问题。这不是夸张——我排查过的轮换事故里,权限不足是最容易踩的坑。为什么?因为轮换不是一个人干活,它涉及好几个角色:轮换工具、密钥存储、目标服务,每个环节都得有对应的权限。

说白了,轮换动作就像接力赛。第一棒是触发轮换的那个人(或脚本),第二棒是密钥管理系统,第三棒是目标应用。任何一棒权限不够,接力棒就掉地上了。今天咱们就按这个思路,把权限检查的要点掰开揉碎。

核心逻辑图 —— 先给个全景,后面再拆细节。

权限不足排查路径图 密钥轮换失败 IAM 角色权限 ACL / 资源策略 云服务自身权限 信任策略 权限边界 服务角色 KMS 密钥策略 S3 存储桶策略 SQS 队列策略 Lambda 执行角色 ECS 任务角色 EC2 实例角色 权限不足 → 轮换失败 (查看日志!) 💡 排查口诀: 谁在轮换? 用什么角色? 是否被策略拒绝了?

4.1 IAM 角色权限:轮换执行者的「身份证」

轮换动作通常不是人按按钮,而是由某个程序触发的——比如 Lambda 函数、CronJob、或者 CI/CD 流水线。这些程序需要一个身份,在 AWS 里就是 IAM 角色。如果这个角色权限不够,第一步就卡住了。

检查信任策略 —— 谁可以扮演这个角色?我记得有次帮客户排查,他们用 Lambda 做密钥轮换,结果 Lambda 一直报 AssumeRole 失败。一看信任策略,Principal 写的是"root",但 Lambda 的服务主体是 "lambda.amazonaws.com",根本不匹配。你想想看,连门都进不去,后面权限再大也没用。

信任策略常见问题 现象 修复方向
Principal 缺失或写错服务主体 AssumeRole 被拒绝 (403) 补上对应的服务主体,如 ecs-tasks.amazonaws.com
条件键限制过严 特定触发条件下能扮演,其他条件失败 检查 aws:SourceArn 等条件,放宽或补全
角色嵌套链限制 跨账户轮换时角色链太长 限制链深度,或用服务管控策略

权限边界 (Permissions Boundary) —— 这个很多人容易忽略。就算角色本身给了 kms:RotateKeyOnDemand,如果角色的权限边界里没放开,那也没用。我个人习惯每次新建轮换角色时,先检查一下有没有绑定边界策略,有的话得确认边界里包含了轮换需要的操作。

// 示例:检查角色是否被权限边界限制了
aws iam get-role --role-name MyKeyRotationRole
// 看输出中的 PermissionsBoundary 字段
// 如果存在,再用 get-policy 查看具体策略
我的一个小技巧: 用IAM策略模拟器 (Policy Simulator) 提前测一遍轮换动作,比翻文档快得多。直接把轮换所需的 API 调用放进去模拟,哪个权限缺失一目了然。我在项目中用这个工具抓出过好几处遗漏的 kms:CreateKey 权限。

4.2 ACL / 资源策略:密钥和数据存储的「门禁」

权限不足不止出在 IAM 角色上。很多时候,密钥本身有资源级策略(比如 KMS 密钥策略),或者密钥关联的数据库、队列也有自己的访问控制。嗯,这里要注意,IAM 和资源策略是独立评估的,两者必须同时允许才能通过。

KMS 密钥策略 —— 轮换密钥时,轮换工具需要 kms:ScheduleKeyDeletion、kms:RotateKeyOnDemand、kms:CreateKey(如果自动生成新密钥)等权限。但密钥策略里如果只写死了 Principal 为某个 Root 账户,没有加上轮换角色的 ARN,那就会报 AccessDenied。

我在项目中遇到过一件事:客户写了一个轮换函数,用了一个自动化角色,但 KMS 密钥策略里只允许了两个管理员账号。每次轮换,日志里就出现 "The ciphertext refers to a customer master key that does not exist, or you do not have permission to use the key" —— 折腾了两天才发现是密钥策略没加上轮换角色。

关键提醒: 密钥策略里即使给了 "kms:RotateKeyOnDemand",也要确认是否需要 "kms:DescribeKey" 或 "kms:GetKeyPolicy"。轮换流程通常会先查一下当前密钥状态,这些读取类的权限也得开放。

S3 存储桶策略 —— 如果你的密钥文件存在 S3(比如 Secrets Manager 后端),或者轮换后需要把新密钥写入某个桶,那桶策略也得允许。尤其跨账户场景,桶策略里要明确写上允许轮换角色的 PutObject、GetObject。

还有 SQS 队列策略,Secrets Manager 有时用队列来异步通知轮换结果。队列策略如果拒绝轮换工具发送消息,那日志里就会有 Publish 超时之类的错误。排查的时候,记得把消息队列和事件通知服务也纳入检查范围。

资源类型 轮换涉及的操作 常见遗漏点
KMS 密钥 RotateKeyOnDemand, CreateKey, EnableKey, PutKeyPolicy 未添加轮换角色 ARN 至密钥策略
S3 存储桶 PutObject, GetObject, ListBucket 跨账户时缺少 Condition(如 aws:SourceArn)
SQS 队列 SendMessage, ReceiveMessage, DeleteMessage 队列策略拒绝非 VPC 端点的请求
Secrets Manager 自身 UpdateSecret, PutSecretValue, RotateSecret 资源策略限制只读账户

4.3 云服务自身权限:轮换「执行环境」的额外限制

前面说的都是主角色和资源策略。但轮换函数跑在具体服务上——Lambda、ECS、或者 EC2,这些服务本身也有自己的权限模型。

Lambda 执行角色 —— 如果轮换函数是 Lambda,它的执行角色必须包含必要的 IAM 策略和信任关系。另外,Lambda 的 VPC 配置也可能导致网络不通,无法访问 KMS 端点。我记得有一次,Lambda 连上了 VPC,但没配置 S3 端点或 NAT,结果轮换到一半,需要读取 Secrets Manager 的备份时超时了。表面看是权限问题,实际上是网络隔离导致的 IO 失败。

ECS 任务角色 —— 在 ECS/Fargate 里跑轮换任务,需要给任务定义一个任务角色 (Task Role)。千万别只给了容器角色 (Execution Role) 而忘了给任务角色。我见过有人把轮换脚本放在 Fargate 上,结果死活连不上 KMS,折腾半天才发现用的是 ECS 服务角色,不是任务角色。

执行角色 vs 任务角色:
  • 执行角色 (Execution Role) — 用于拉取镜像、写入 CloudWatch 日志。
  • 任务角色 (Task Role) — 用于任务内部调用 AWS API,比如 kms:RotateKeyOnDemand。

轮换功能用的是 任务角色,检查时务必确认它有没有轮换相关策略。

EC2 实例角色 —— 如果轮换是跑在 EC2 上(比如 Ansible 脚本),那得给实例附加一个实例角色。实例角色默认会拿到临时凭证,但如果实例不在标准元数据服务范围内(比如使用了 IMDSv2 且配置了高跳数限制),也会拿不到正确的凭证。

4.4 快速排查清单

每次接到轮换失败的工单,我会按这个顺序查一遍,效率很高:

  1. 查日志 — CloudTrail 里搜 AccessDenied 或 UnauthorizedOperation,记下具体的 API 调用和资源 ARN。
  2. 确认谁在调用 — 从日志里找到调用者的角色 ARN / 主体。是不是预期角色?
  3. 模拟策略 — IAM Policy Simulator,用该角色模拟刚才失败的 API 调用。如果模拟失败,那就是策略问题。
  4. 检查资源策略 — 到对应资源(KMS、S3、SQS)查看资源策略,是否包含了该角色?
  5. 检查网络边界 — 如果用的是 VPC Endpoint,检查端点策略是否允许。
  6. 检查服务控制策略 (SCP) — 多账户场景,根组织级的 SCP 可能限制了 kms 操作。
曾经有个案例让我印象深刻: 一个客户在 AWS China 区域做密钥轮换,怎么都不成功。CloudTrail 里没有任何日志,最后发现是 SCP 里直接 Deny 了 kms:RotateKeyOnDemand,而且 SCP 是主账号全局拒绝的,子账号根本无法更改。这种属于组织级策略,排查时别忘了上升一层。

4.5 总结一下

权限不足导致的轮换失败,本质上就三类问题:

  • 谁的身份不对 — 信任策略没写对,角色扮演不了。
  • 能做什么没给够 — IAM 策略缺少关键操作,或权限边界挡住了。
  • 资源方不让进 — 密钥策略、桶策略等资源级策略没放行。

排查的时候,记住「身份→策略→边界」三步法,再结合 CloudTrail 日志,基本十分钟内能定位。别一上来就怀疑代码——我见过太多人改代码改了一周,结果只是密钥策略少写了一个 ARN。你想想看,多冤啊。