cloud-sre
排查 AWS Glue iam:PassRole AccessDenied 的完整过程
从 Glue 控制台 updateJob 报错出发,定位到 IAM 组策略、托管策略范围、MFA 限制策略和最终模拟验证的排查记录。
一次 AWS Glue Job 在控制台保存时报错,错误信息指向
iam:PassRole。表面上看用户已经有 Glue Console 的完整权限,但仍然不能
更新 Job。
这类问题的关键点是:glue:UpdateJob 和 iam:PassRole 是两件事。用户能操作
Glue,不代表用户可以把某个 IAM Role 传给 Glue 服务。
下面的示例已做匿名化处理:
| 项目 | 示例 |
|---|---|
| 人工用户 | arn:aws:iam::<account-id>:user/<human-user> |
| Glue Job | <glue-job-name> |
| Runtime Role | arn:aws:iam::<account-id>:role/<glue-runtime-role> |
| 用户组 | GlueAccess |
文中用语说明
| 用语 | 含义 |
|---|---|
iam:PassRole | 允许用户把某个 IAM Role 交给 AWS 服务使用的权限。Glue Job 使用 runtime role 时会用到它。 |
| Runtime Role | Glue Job 运行时 assume 的 IAM Role,决定 Job 可以读写哪些资源。 |
| Trust policy | 写在 IAM Role 上的信任关系,说明哪个 AWS 服务或 principal 可以 assume 这个 role。 |
explicitDeny | IAM simulator 的结果,表示命中了明确拒绝。它会覆盖 allow。 |
implicitDeny | IAM simulator 的结果,表示没有任何 allow 覆盖这个请求。没有显式拒绝,但仍然不允许。 |
最开始失败在哪里
控制台报错类似这样:
Failed to update job
updateJob: AccessDeniedException:
User: arn:aws:iam::<account-id>:user/<human-user>
is not authorized to perform: iam:PassRole
on resource: arn:aws:iam::<account-id>:role/<glue-runtime-role>
because no identity-based policy allows the iam:PassRole action
这段报错里最重要的不是 Failed to update job,而是被拒绝的 action:
iam:PassRole。也就是说,失败点不是单纯缺少 glue:UpdateJob,而是用户不能把
这个 runtime role 交给 Glue。
确认排查账号
第一步先确认 CLI 使用的 profile 和控制台报错里的 AWS account 是同一个。
aws sts get-caller-identity --profile <production-profile>
返回的 account ID 和报错中的 account ID 一致,说明后续 IAM 查询没有查错账号。
找到用户权限来源
先看用户本身有没有直接挂策略:
aws iam list-attached-user-policies \
--user-name <human-user> \
--profile <production-profile>
aws iam list-user-policies \
--user-name <human-user> \
--profile <production-profile>
结果显示用户没有直接 attached policy,也没有 inline user policy。
接着查用户所在的组:
aws iam list-groups-for-user \
--user-name <human-user> \
--profile <production-profile>
用户属于 GlueAccess 和一个通用开发者组。于是问题范围收窄为:哪个组策略应该
允许这个用户执行 iam:PassRole?
检查 Glue Role 本身
目标 role 本身不是问题。读取 role:
aws iam get-role \
--role-name <glue-runtime-role> \
--profile <production-profile>
它的 trust policy 允许 Glue assume:
{
"Effect": "Allow",
"Principal": {
"Service": "glue.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
这排除了 role trust relationship 的问题。只要用户能 pass 这个 role,Glue 服务就 可以 assume 它。
确认 Job 使用的就是这个 Role
再直接读取 Glue Job:
aws glue get-job \
--job-name <glue-job-name> \
--region ap-northeast-1 \
--profile <production-profile> \
--query "Job.{Name:Name,Role:Role,LastModifiedOn:LastModifiedOn}"
返回的 Job.Role 和控制台报错里的 role 一致。这样就把 UI 报错和一个具体 IAM
resource 对上了。
模拟被拒绝的 Action
接下来用 IAM policy simulator 区分三种可能:
| 推断 | 证明方式 |
|---|---|
| Role trust 配错 | get-role 的 trust policy 不包含 Glue |
| 有限制策略显式拒绝 | simulator 返回 explicitDeny |
| 没有策略允许 pass 这个 role | simulator 返回 implicitDeny |
先模拟这个用户对这个 role 执行 iam:PassRole,并指定目标服务是 Glue:
aws iam simulate-principal-policy \
--profile <production-profile> \
--policy-source-arn arn:aws:iam::<account-id>:user/<human-user> \
--action-names iam:PassRole \
--resource-arns arn:aws:iam::<account-id>:role/<glue-runtime-role> \
--context-entries \
ContextKeyName=iam:PassedToService,ContextKeyValues=glue.amazonaws.com,ContextKeyType=string
第一次模拟命中了 MFA 限制策略,结果是 explicitDeny。这个状态也是真实存在的:
账号里有一条策略,在用户没有 MFA 的时候拒绝大部分动作。
但这还不是完整原因。继续补上 MFA 已存在、来源满足限制策略的上下文:
aws iam simulate-principal-policy \
--profile <production-profile> \
--policy-source-arn arn:aws:iam::<account-id>:user/<human-user> \
--action-names iam:PassRole \
--resource-arns arn:aws:iam::<account-id>:role/<glue-runtime-role> \
--context-entries \
ContextKeyName=iam:PassedToService,ContextKeyValues=glue.amazonaws.com,ContextKeyType=string \
ContextKeyName=aws:MultiFactorAuthPresent,ContextKeyValues=true,ContextKeyType=boolean
排除限制策略后,结果变成 implicitDeny。这说明即使 MFA 和来源 IP 条件都满足,
仍然没有任何 allow statement 覆盖这个 role。
找到缺失的 Allow
GlueAccess 组挂了 AWS 托管策略 AWSGlueConsoleFullAccess。
这个策略确实包含 iam:PassRole,但它只允许传递符合 AWS Glue service role
命名规则的 role:
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/AWSGlueServiceRole*",
"Condition": {
"StringLike": {
"iam:PassedToService": "glue.amazonaws.com"
}
}
}
它也允许 service-role 路径下的同类 role:
arn:aws:iam::*:role/service-role/AWSGlueServiceRole*
但当前 Job 使用的是自定义命名的 runtime role,不是 AWSGlueServiceRole*。所以
即使用户有 Glue Console Full Access,仍然不能 pass 这个 role。
最小权限改动
最小修复是给 GlueAccess 组新增一条 inline policy:
aws iam put-group-policy \
--profile <production-profile> \
--group-name GlueAccess \
--policy-name AllowPassGlueRuntimeRoleToGlue \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPassGlueRuntimeRoleToGlue",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::<account-id>:role/<glue-runtime-role>",
"Condition": {
"StringEquals": {
"iam:PassedToService": "glue.amazonaws.com"
}
}
}
]
}'
这条权限只允许 pass 一个指定 role,并且只能传给 glue.amazonaws.com。
检查改动是否生效
先读回组策略:
aws iam get-group-policy \
--profile <production-profile> \
--group-name GlueAccess \
--policy-name AllowPassGlueRuntimeRoleToGlue
然后用同样的 principal、action、resource 和 Glue service context 再跑一次 simulator。结果变成:
allowed
这比让用户刷新控制台再试更可靠,因为 simulator 已经显示失败的 IAM action 被 identity-based policy 覆盖。
下次遇到 Glue PassRole 失败时
遇到 Glue Job 更新时报 iam:PassRole,可以按这个顺序查:
- 确认 CLI profile 和控制台报错在同一个 AWS account。
- 查用户直接挂载的策略。
- 查用户所在组和组策略。
- 查目标 role 的 trust policy。
- 查 Glue Job 当前使用的 role。
- 用
iam:PassedToService=glue.amazonaws.com模拟iam:PassRole。 - 如果结果是
explicitDeny,先看 MFA、IP、SCP、permission boundary 等限制策略。 - 如果结果是
implicitDeny,补一条最小范围的 allow。 - 修复后先重跑 simulator,再让用户回控制台重试。
这次保留下来的规则
glue:* 和 AWSGlueConsoleFullAccess 不等于“可以 pass 任意 Glue role”。
iam:PassRole 是独立的 IAM action,AWS 托管策略也可能只覆盖符合服务角色命名
规则的 role。
更稳妥的授权模型是:
允许 iam:PassRole
只作用在这个 Glue Job 需要的 runtime role 上
并且只允许传给 glue.amazonaws.com