iam:PassRole is the permission that lets one identity attach an IAM role to an AWS service, such as a function or a compute instance. A deploy role needs it when the pipeline creates those resources. Scope it to specific role ARNs, or it can become a path to more power than you meant to give.
What passing a role means
Many AWS services run work on your behalf using a role you give them. You configure that once, and the service assumes the role later. AWS's documentation explains it plainly: to pass a role to a service, a user must have permission to pass the role to that service. This helps administrators make sure only approved users can configure a service with a role that grants permissions.
A concrete case: your pipeline deploys a function. The function runs with an execution role. The pipeline's own role must be allowed to pass that execution role, or the create call fails with an access denied error.
Why it is an escalation risk
AWS gives the example directly. Alice might not be allowed to perform any S3 actions. If Alice could pass a role that allows S3 actions to a service, the service could perform those actions when executing the job. The risk is not the pass itself. It is the gap between what the CI role can do and what the passed role can do.
So an unrestricted PassRole on a CI role is a quiet way to turn "can deploy a function" into "can do whatever the most powerful role in the account can do".
How to scope it
- List the exact roles your pipeline needs to pass. Usually it is one to three execution roles.
- Put their ARNs, or a tight naming prefix, in the Resource element, not a star.
- Add the
iam:PassedToServicecondition so each role can only go to the intended service. - Pair
iam:PassRolewithiam:GetRoleif your tooling reads the role first, as AWS's example does. - Keep the passed roles themselves small. Their permissions are part of the CI role's reach.
A scoped statement looks like this:
{
"Effect": "Allow",
"Action": ["iam:GetRole", "iam:PassRole"],
"Resource": "arn:aws:iam::111122223333:role/app-exec-*",
"Condition": {
"StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" }
}
}
Two gotchas from the docs
First, AWS warns against controlling who can pass a role by tagging the role and using a resource tag condition with PassRole, saying the approach does not give reliable results. Use ARNs.
Second, PassRole is a permission, not an API call, so no CloudTrail event is generated for it. To see which role was passed, read the log entry for the call that created or changed the resource, for example the function creation event. This is also why Access Analyzer's generated policies leave it out.
Reviewing an existing CI role
Search the role's policies for PassRole with a star resource. If you find one, work backward: which roles exist in the account, which have broad permissions, and could the pipeline pass them? Replace the star with the short list from step 1 and rerun the pipeline in a test account.
Quick check
Is PassRole logged in CloudTrail?
No. AWS says it is a permission, not an API call. Look at the event that created the resource to see which role was passed.
Can I limit PassRole by tagging roles?
AWS advises against it, noting the resource tag approach does not give reliable results. Use role ARNs plus the PassedToService condition.
Safeguard does not manage your cloud accounts. It scans your code and dependencies, applies pull request policies and gates, and automates compliance evidence. Free scan: gold.safeguard.sh/scan.
Sources
- AWS IAM User Guide: Grant a user permissions to pass a role to an AWS service
- AWS IAM User Guide: IAM Access Analyzer policy generation
Last reviewed: 19 October 2026.