智能硬件行业资讯,IoT、机器人、AR/VR、智能家居前沿

AWS AccessDenied 排查记录:从 IAM 策略到资源策略的权限不足定位思路

AWS AccessDenied 排查记录:从 IAM 策略到资源策略的权限不足定位思路 - 图片1

AWS AccessDenied 排查记录:从 IAM 策略到资源策略的权限不足定位思路 - 图片2

AWS AccessDenied 排查记录:从 IAM 策略到资源策略的权限不足定位思路 - 图片3

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 Key;ECS 任务以为用的是某个 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 为例: import boto3 sts = boto3.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 \ --bucket demo-bucket \ --key test.txt \ --body ./test.txt 如果报错 s3:PutObject,检查 IAM Policy 是否允许对象 ARN: arn:aws:s3:::demo-bucket/* 如果是 ListObjectsV2 或 ListBucket 报错,检查 bucket ARN: arn: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 AccessDenied:IAM 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 找真实失败事件 如果报错信息太短,或者应用日志只打印了 AccessDeniedException,CloudTrail 通常能提供更多线索。 可以在 CloudTrail Event history 里按这些条件查: Event source,比如 s3.amazonaws.com、kms.amazonaws.comEvent name,比如 PutObject、DecryptUser name 或 Role session nameError code:AccessDenied、AccessDeniedException、UnauthorizedOperation CloudTrail 里重点看: 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 登录缓存 如果你以为自己用了 dev profile,但环境变量里还有另一组 Access Key,SDK 可能优先读取环境变量。 可以临时检查: env | grep AWS 执行 CLI 时明确指定 profile: aws s3 ls --profile dev 如果是 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 权限不足问题都能定位到具体策略,而不是靠反复试权限碰运气。