The Misunderstood Dynamics of iam:PassRole
Most cloud security audits focus heavily on direct privilege assignment actions like iam:CreateUser or iam:AttachUserPolicy, while treating iam:PassRole as a secondary utility permission. That distinction represents a major blind spot: iam:PassRole is not an administrative action on its own, but rather a delegation operator that allows a user to assign permissions to AWS compute services.
When an identity possesses iam:PassRole alongside permission to configure or launch an AWS service—such as an EC2 instance, Lambda function, or ECS task—it can execute code under the security context of whatever execution role it passes. If an account contains a high-privileged service role (such as a deployment role with AdministratorAccess), a low-privileged identity with wildcard iam:PassRole access can bridge the gap to full account compromise instantly.
Mechanics of Service Delegation
The escalation vector relies on two distinct authorization checks inside AWS. First, the IAM engine evaluates whether the initiating identity has permission to invoke iam:PassRole on the target role. Second, AWS validates whether the destination service is trusted by the target role’s AssumeRolePolicyDocument.
Consider a scenario where an identity holds restricted operational access, but possesses iam:PassRole scoped to * alongside lambda:CreateFunction. The operational sequence functions as follows:
- Target Identification: The user queries the IAM environment to identify existing roles containing administrative or broad management policies (e.g.,
arn:aws:iam::123456789012:role/DevOpsAdminRole). - Payload Configuration: The user constructs a serverless function payload designed to perform privileged actions, such as attaching full administrator policies or returning temporary security credentials.
- Service Context Assumption: The user creates and invokes the Lambda function, passing the high-privilege execution role.
Using the AWS CLI, creating such a serverless resource demonstrates how iam:PassRole is evaluated at resource creation time:
aws lambda create-function \
--function-name SystemMaintenance \
--runtime python3.11 \
--role arn:aws:iam::123456789012:role/DevOpsAdminRole \
--handler index.handler \
--zip-file fileb://payload.zip \
--region us-east-1
When invoked via aws lambda invoke --function-name SystemMaintenance output.json, the Lambda service assumes DevOpsAdminRole, requests temporary STS credentials from the control plane, and executes the payload inside an environment granted full administrative authority.
Scoping Down iam:PassRole Access
Mitigating this risk requires eliminating wildcards from iam:PassRole policy statements. Granting Resource: "*" in a PassRole statement is functionally equivalent to distributing administrative privileges if any high-privilege roles exist in the account.
To properly secure iam:PassRole, policies must enforce specific resource ARNs and restrict which services can receive the role using the iam:PassedToService condition key:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::123456789012:role/app-specific-lambda-role",
"Condition": {
"StringEquals": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
}
]
}
The iam:PassedToService key ensures that even if an identity attempts to pass a role to an unauthorized service (such as EC2 or Glue), the request is rejected at the API level.
Enforcing Delegation Boundaries with Service Control Policies
In enterprise environments, relying solely on inline or managed IAM policies created by local account administrators creates drift. Service Control Policies (SCPs) at the AWS Organizations level provide a central mechanism to enforce boundaries across all member accounts.
To block users from passing elevated roles or bypassing architecture guidelines, organizations can enforce Permission Boundaries on all role delegation operations. An SCP can explicitly deny iam:PassRole unless the destination role includes an approved boundary constraint or matches a designated naming convention:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictUnboundedRolePassing",
"Effect": "Deny",
"Action": [
"iam:PassRole"
],
"Resource": "arn:aws:iam::*:role/*",
"Condition": {
"StringNotLike": {
"iam:ResourceTag/RoleClass": "DelegatedWorkload"
}
}
}
]
}
By pairing mandatory resource tagging or Permission Boundaries with strict iam:PassedToService condition checks, security teams effectively isolate compute workloads and close the delegation escalation path across the entire organization.
Related content
Want a second set of eyes on your security posture?
Let's talk about where your real exposure is.
Book an advisory call