Ninety seconds, no audio

The permission that is not in the log.

Your agent's role is not an administrator. How it becomes one with two ordinary calls, why the audit trail has no event for the moment it happened, and the two lines of policy that stop it. The captions carry the narration; space plays and pauses, the arrow keys step a scene.

1 / 6 · The small role
agent-runner, allowed
s3:GetObject
sqs:SendMessage
lambda:InvokeFunction
lambda:CreateFunction
iam:PassRole
Resource: *
This role is not an administrator. Read it line by line and nothing is alarming.
It can create a function. It can pass a role to a service. Both are ordinary.
Read the two lines together instead.
It is not an administrator. It can become one.
2 / 6 · The move
agent.log
02:10:04CreateFunction helper, role=pipeline-exec
02:10:09Invoke helper
pipeline-exec, trusted by Lambda
s3:*
dynamodb:*
iam:*
0 DENIED
Create a function. Hand it the strongest role that Lambda is allowed to use.
Invoke it. Two calls, both allowed, because both were granted.
Nothing was exploited. There is no vulnerability here to patch.
The function runs as that role, and the agent holds the function.
3 / 6 · The search
CloudTrail · event history
searchEventName = PassRole
 No events found
CreateFunction · requestParameters
namehelper
rolearn:aws:iam::ACCOUNT:role/pipeline-exec
So look it up. Search the trail for the moment the role was passed.
There is nothing to find.
AWS's own words: PassRole is not an API call. It is a permission, so no event is written for it.
The evidence is inside the call that used it. You have to know to look there.
4 / 6 · The fix
agent-runner, iam:PassRole
Resource: *
Resource: arn:aws:iam::ACCOUNT:role/agent-task-*
Condition: iam:PassedToService = lambda.amazonaws.com
tag the role instead
PASS DENIED
Name the roles that may be passed. A wildcard here is the whole account.
Bound it further by the one service they may be passed to.
Not by tagging the role. AWS says that does not have reliable results.
Two lines of policy, and the move in scene two is refused.
5 / 6 · What it does not fix
agent-task-runner, allowed
s3:GetObject, s3:PutObject
dynamodb:Query, dynamodb:PutItem
bedrock:InvokeModel
secretsmanager:GetSecretValue
sqs:SendMessage
Naming the roles closes one path. It does not make the named role small.
The agent still reaches everything the role you named can do.
And roles already handed to running functions keep what they have.
Least privilege bounds reach. It cannot read intent.
6 / 6 · Two commands
terminal · read-only
$aws iam get-account-authorization-details --filter Role > roles.json
$grep -c '"iam:PassRole"' roles.json
abacross.com/readiness
Flags an agent role that may pass any role, and names what it does not read.
Two read-only commands. Nothing leaves your machine.
Every role that can pass a role. If the answer is a wildcard, you have scene one.
The free readiness check now flags it, and says what it does not read.
0:00 / 0:00
The argument, in six lines

It is not an administrator. It can become one.

1

The small role

The agent may create a function, invoke it, and pass a role, on every role. Line by line, nothing is alarming.

2

The move

Create a function, hand it the strongest role that Lambda is allowed to assume, invoke it. Two calls, both granted. Nothing is exploited, and the function runs as that role.

3

The search

Search CloudTrail for PassRole and there is nothing: AWS says it is a permission, not an API call, so no event is written for it. The role is inside the record of the call that used it.

4

The fix

Name the roles that may be passed, and pin the one service with iam:PassedToService. Not role tags: AWS says that does not have reliable results.

5

What it does not fix

Naming a role does not make that role small, and roles already handed to running functions keep what they have. Least privilege bounds reach; it cannot read intent.

6

Two commands

Two read-only commands list every role that can pass a role. The free readiness check now flags an agent role that may pass any role, in its inline policies, and says what it does not read.

Run it: the free readiness check. AWS's own page on it: granting a user permission to pass a role. Google Cloud has the same shape in the iam.serviceAccounts.actAs permission, and Azure in the Managed Identity Operator role. Share this one: MP4, 1080p, 2.2 MB, or on YouTube.