cloud-sre

排查 AWS Glue iam:PassRole AccessDenied 的完整过程

从 Glue 控制台 updateJob 报错出发,定位到 IAM 组策略、托管策略范围、MFA 限制策略和最终模拟验证的排查记录。

Jun 17, 2026
AWSGlueIAMPassRoletroubleshooting

一次 AWS Glue Job 在控制台保存时报错,错误信息指向 iam:PassRole。表面上看用户已经有 Glue Console 的完整权限,但仍然不能 更新 Job。

这类问题的关键点是:glue:UpdateJobiam:PassRole 是两件事。用户能操作 Glue,不代表用户可以把某个 IAM Role 传给 Glue 服务。

下面的示例已做匿名化处理:

项目示例
人工用户arn:aws:iam::<account-id>:user/<human-user>
Glue Job<glue-job-name>
Runtime Rolearn:aws:iam::<account-id>:role/<glue-runtime-role>
用户组GlueAccess

文中用语说明

用语含义
iam:PassRole允许用户把某个 IAM Role 交给 AWS 服务使用的权限。Glue Job 使用 runtime role 时会用到它。
Runtime RoleGlue Job 运行时 assume 的 IAM Role,决定 Job 可以读写哪些资源。
Trust policy写在 IAM Role 上的信任关系,说明哪个 AWS 服务或 principal 可以 assume 这个 role。
explicitDenyIAM simulator 的结果,表示命中了明确拒绝。它会覆盖 allow。
implicitDenyIAM 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 这个 rolesimulator 返回 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,可以按这个顺序查:

  1. 确认 CLI profile 和控制台报错在同一个 AWS account。
  2. 查用户直接挂载的策略。
  3. 查用户所在组和组策略。
  4. 查目标 role 的 trust policy。
  5. 查 Glue Job 当前使用的 role。
  6. iam:PassedToService=glue.amazonaws.com 模拟 iam:PassRole
  7. 如果结果是 explicitDeny,先看 MFA、IP、SCP、permission boundary 等限制策略。
  8. 如果结果是 implicitDeny,补一条最小范围的 allow。
  9. 修复后先重跑 simulator,再让用户回控制台重试。

这次保留下来的规则

glue:*AWSGlueConsoleFullAccess 不等于“可以 pass 任意 Glue role”。 iam:PassRole 是独立的 IAM action,AWS 托管策略也可能只覆盖符合服务角色命名 规则的 role。

更稳妥的授权模型是:

允许 iam:PassRole
只作用在这个 Glue Job 需要的 runtime role 上
并且只允许传给 glue.amazonaws.com