AWS AccessDenied 排查记录从 IAM 策略到资源策略的权限不足定位思路做 AWS 开发或运维时AccessDenied基本绕不开。有时候是在控制台点一个按钮提示权限不足有时候是 CLI 执行命令失败有时候应用日志里只留下一句AccessDeniedException: User is not authorized to perform this action这类问题看起来像“账号没权限”但真正排查时不能只盯着 IAM 用户本身。AWS 权限判断链路比较长IAM 策略、角色信任关系、资源策略、SCP、权限边界、会话策略、KMS Key Policy 都可能参与判断。少看一层就容易误判。下面按实际排查思路整理一遍适合遇到 AWS 权限不足、AWS AccessDenied、AWS IAM 权限错误时做快速定位。先看清楚报错里缺的是哪个 Action排查 AccessDenied不建议一上来就去 IAM 控制台乱加权限。第一步先把错误信息读完整尤其看这几个字段哪个身份在请求User、Role、AssumedRole 还是某个服务角色被拒绝的 Action 是什么访问的是哪个 Resource是否出现explicit deny是否提示和组织策略、资源策略、KMS、权限边界有关例如 CLI 报错可能是这样An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:iam::123456789012:user/dev-user is not authorized to perform: s3:PutObject on resource: arn:aws:s3:::demo-bucket/test.txt这条信息至少说明三件事当前身份是dev-user缺的是s3:PutObject目标资源是arn:aws:s3:::demo-bucket/test.txt如果只给用户加了s3:GetObject当然还是会失败。很多 AWS IAM 权限错误其实不是大问题而是 Action 和 Resource 没对上。再比如这个User: arn:aws:sts::123456789012:assumed-role/app-role/session-name is not authorized to perform: kms:Decrypt这里就不是单纯 S3 权限了。应用可能在读取加密对象、拉取密钥、访问加密数据库时触发了 KMS 解密结果当前角色没有kms:Decrypt或者 KMS Key Policy 没放行。确认当前程序实际用的是哪个身份很多人排查 AWS AccessDenied 时会看错身份。本地开发以为用的是自己的 IAM User实际 SDK 读到了环境变量里的 Access KeyECS 任务以为用的是某个 Task Role结果容器里挂了旧凭证EC2 上以为是实例角色实际上应用配置里写死了另一组密钥。最直接的确认方式是执行aws sts get-caller-identity返回结果类似{UserId:AROAXXXXX:session-name,Account:123456789012,Arn:arn:aws:sts::123456789012:assumed-role/app-role/session-name}这里的Arn才是当前请求真正使用的身份。如果是应用代码可以临时在启动阶段打印当前身份。以 Python boto3 为例importboto3 stsboto3.client(sts)print(sts.get_caller_identity())排查权限问题时这一步很重要。因为你给 A 角色加权限程序实际用的是 B 角色后面怎么改都不会生效。区分“没有允许”和“显式拒绝”AWS 权限判断里默认是拒绝。也就是说如果没有任何策略允许某个操作请求会被拒绝。但更麻烦的是显式拒绝也就是策略里存在Deny。一旦命中显式拒绝即使其他策略里有Allow最终还是拒绝。常见报错里可能会看到with an explicit deny in an identity-based policy或者with an explicit deny in a service control policy看到explicit deny时不要继续给用户追加 Allow 权限。先找 Deny 来源。常见位置包括IAM 用户、组、角色上的身份策略权限边界 Permission BoundaryAWS Organizations 的 SCPS3 Bucket Policy、KMS Key Policy 等资源策略STS AssumeRole 时附带的会话策略一个典型的 Deny 策略可能长这样{Effect:Deny,Action:s3:*,Resource:*,Condition:{StringNotEquals:{aws:RequestedRegion:ap-southeast-1}}}这类策略可能限制只能访问某个区域或者只能从指定 IP、指定 VPC Endpoint、指定标签条件访问。命中条件后单独加s3:PutObject没用。IAM 身份策略Action、Resource、Condition 都要对上最常见的 AWS 权限不足还是 IAM Policy 写得不完整。比如允许上传 S3 对象至少要允许对应 bucket 下对象资源{Effect:Allow,Action:[s3:PutObject],Resource:[arn:aws:s3:::demo-bucket/*]}注意这里是arn:aws:s3:::demo-bucket/*不是arn:aws:s3:::demo-bucket前者表示 bucket 里的对象后者表示 bucket 本身。像s3:ListBucket需要 bucket ARN{Effect:Allow,Action:[s3:ListBucket],Resource:[arn:aws:s3:::demo-bucket]}很多 S3 权限错误就出在这里对象操作和 bucket 操作的 Resource 写法不一样。再看 EC2。启动实例常见不只是ec2:RunInstances还可能涉及 AMI、Subnet、SecurityGroup、KeyPair、IAM Role 传递等。如果报错里出现iam:PassRole说明不是 EC2 本身没权限而是当前身份不能把某个 IAM Role 传给 EC2、ECS、Lambda 等服务。需要类似这样的权限{Effect:Allow,Action:iam:PassRole,Resource:arn:aws:iam::123456789012:role/app-instance-role}实际生产环境不建议直接放Resource: *, 至少要限制到明确角色范围。Role 相关问题不仅要看权限策略还要看信任关系如果应用通过 AssumeRole 切换角色排查时要看两部分第一调用方有没有权限执行sts:AssumeRole第二被 Assume 的角色信任关系是否允许调用方进入。调用方策略示例{Effect:Allow,Action:sts:AssumeRole,Resource:arn:aws:iam::123456789012:role/target-role}目标角色的信任策略需要允许来源身份{Effect:Allow,Principal:{AWS:arn:aws:iam::123456789012:role/source-role},Action:sts:AssumeRole}如果是 EC2、ECS、Lambda 等服务角色Principal 又不一样。例如 Lambda 常见是{Effect:Allow,Principal:{Service:lambda.amazonaws.com},Action:sts:AssumeRole}所以遇到角色权限问题不要只看角色挂了哪些策略。信任关系不对角色根本进不去进不去之后后面的权限策略也没有机会生效。S3 AccessDenied重点检查 Bucket Policy 和对象权限S3 的 AccessDenied 很常见而且经常不是 IAM 单点问题。排查顺序可以这样走先确认当前身份aws sts get-caller-identity再确认具体操作aws s3api put-object\--bucketdemo-bucket\--keytest.txt\--body./test.txt如果报错s3:PutObject检查 IAM Policy 是否允许对象 ARNarn:aws:s3:::demo-bucket/*如果是ListObjectsV2或ListBucket报错检查 bucket ARNarn:aws:s3:::demo-bucket然后看 Bucket Policy 有没有 Deny。比如限制来源 VPC Endpoint、限制 IP、要求 TLS、要求特定 ACL、限制 Principal都可能导致 AccessDenied。有些 bucket policy 会写类似条件{Effect:Deny,Principal:*,Action:s3:*,Resource:[arn:aws:s3:::demo-bucket,arn:aws:s3:::demo-bucket/*],Condition:{Bool:{aws:SecureTransport:false}}}这表示非 HTTPS 请求会被拒绝。它本身是合理的安全限制但如果应用、代理或工具链请求方式异常就会触发拒绝。如果对象使用 KMS 加密还要继续检查 KMS 权限。S3 报 AccessDenied不一定只和 S3 有关。KMS AccessDeniedIAM Policy 和 Key Policy 都可能拦截KMS 是权限排查里比较容易漏的一层。比如应用读取一个 SSE-KMS 加密的 S3 对象IAM 里有s3:GetObject但仍然失败报错可能指向kms:Decrypt这时要检查两处。当前身份是否有 KMS 操作权限{Effect:Allow,Action:[kms:Decrypt,kms:DescribeKey],Resource:arn:aws:kms:ap-southeast-1:123456789012:key/xxxx-xxxx-xxxx}同时KMS Key Policy 是否允许该身份使用这把 Key。KMS 的特殊点在于很多场景下只改 IAM Policy 不够Key Policy 也要放行。如果是跨账号访问 KMS加上资源策略、账号信任、服务调用链后会更复杂建议结合 CloudTrail 看最终失败在哪个调用上。Organizations SCP账号层面的限制最容易被忽略如果 AWS 账号在 Organizations 下面SCP 可能限制了某些服务、区域或高危操作。SCP 不直接授予权限只负责设置账号或 OU 的权限上限。也就是说IAM Policy 允许但 SCP 不允许最终不允许IAM Policy 不允许SCP 允许也不会自动获得权限典型场景是组织层面禁止使用某些区域结果用户在控制台切到其他 Region 创建资源时提示权限不足。报错里如果出现service control policy就要去 Organizations 里看当前账号所在 OU 绑定了哪些 SCP。开发团队不一定有 Organizations 权限这时需要找云管理员确认。不要在业务角色上反复加权限方向错了。权限边界 Permission Boundary角色看起来有权限实际被上限卡住Permission Boundary 也很容易造成误判。一个 IAM Role 上可能挂了很宽的 Allow 策略但如果它同时设置了权限边界那么最终权限不能超过边界允许的范围。例如角色策略允许{Effect:Allow,Action:ec2:*,Resource:*}但权限边界只允许 S3那么 EC2 操作依然会失败。排查时在 IAM 控制台查看对应用户或角色确认有没有 Permission Boundary。CLI 也可以查角色信息aws iam get-role --role-name app-role返回里如果有PermissionsBoundary就要继续看边界策略内容。用 CloudTrail 找真实失败事件如果报错信息太短或者应用日志只打印了AccessDeniedExceptionCloudTrail 通常能提供更多线索。可以在 CloudTrail Event history 里按这些条件查Event source比如s3.amazonaws.com、kms.amazonaws.comEvent name比如PutObject、DecryptUser name 或 Role session nameError codeAccessDenied、AccessDeniedException、UnauthorizedOperationCloudTrail 里重点看userIdentityeventNamerequestParametersresourceserrorCodeerrorMessage有时应用层看到的是一个失败CloudTrail 里能看到背后连续多个 AWS API 调用。比如创建资源时主操作失败真正缺的权限可能是iam:PassRole、ec2:CreateTags或kms:CreateGrant。用 IAM Policy Simulator 做策略验证AWS 提供 IAM Policy Simulator可以用来验证某个用户、角色在某个 Action 和 Resource 上是否会被允许。适合验证这类问题某个角色是否允许s3:PutObject某个用户是否允许ec2:StartInstances某个策略条件是否会命中某个资源 ARN 是否写错不过要注意模拟器适合看 IAM 身份策略和部分上下文不一定能完整覆盖所有实际运行因素。像某些资源策略、服务内部调用、组织层限制、运行时会话条件仍然要结合实际报错和 CloudTrail 判断。开发环境里常见的几个坑本地开发经常是凭证混用。AWS CLI 和 SDK 会按默认凭证链查找身份常见来源包括环境变量里的AWS_ACCESS_KEY_ID~/.aws/credentials~/.aws/config指定的 profileEC2 Instance ProfileECS Task RoleEKS IRSASSO 登录缓存如果你以为自己用了devprofile但环境变量里还有另一组 Access KeySDK 可能优先读取环境变量。可以临时检查env|grepAWS执行 CLI 时明确指定 profileaws s3ls--profiledev如果是 SDK也要确认代码里是否指定了 profile、region、role ARN。权限排查时身份和区域都要确认不然很容易走偏。生产环境别直接用管理员权限兜底遇到 AccessDenied最省事的做法是挂AdministratorAccess。但生产环境不建议这么处理。更稳妥的方式是按最小权限原则补齐必要权限根据报错确认缺失 Action根据业务范围确认 Resource必要时增加 Condition 限制来源、标签、区域或账号在测试环境验证再同步到生产角色例如应用只需要读取某个 bucket 下的文件就不要给s3:*和Resource: *。可以收敛成类似{Effect:Allow,Action:[s3:GetObject],Resource:[arn:aws:s3:::demo-bucket/app-prefix/*]}如果还需要列目录再补{Effect:Allow,Action:[s3:ListBucket],Resource:[arn:aws:s3:::demo-bucket],Condition:{StringLike:{s3:prefix:app-prefix/*}}}这样比直接开放整个 bucket 更可控。一份排查清单遇到 AWS AccessDenied可以按这个顺序看用aws sts get-caller-identity确认当前身份从报错里提取 Action、Resource、Region检查 IAM 用户或角色上的身份策略看是否存在explicit deny检查 Permission Boundary如果账号属于 Organizations确认 SCP 是否限制如果访问 S3、KMS、SQS、SNS、Secrets Manager 等资源检查资源策略如果涉及 AssumeRole检查调用方权限和目标角色信任关系用 CloudTrail 查真实失败事件用 Policy Simulator 做策略验证按最小权限补齐策略不要直接上管理员权限AWS IAM 权限错误看起来零散但核心思路其实固定先确认“谁”在访问再确认“做什么操作”最后确认“对哪个资源”被哪一层策略拦住。只要把身份、Action、Resource、Deny 来源这几项拆清楚大多数 AWS 权限不足问题都能定位到具体策略而不是靠反复试权限碰运气。