Hardening AWS IAM: Blue Team PassRole Defense Guide

Hardening AWS IAM: Blue Team PassRole Defense Guide

Overview & Defensive Context: AWS IAM Privilege Escalation & iam:PassRole (T1078.004)#

Harden AWS IAM against PassRole privilege escalation: scope Resource ARNs, enforce iam:PassedToService, and deploy permission boundaries.

In our morning threat architecture analysis, we deconstructed the offensive mechanics of AWS IAM Privilege Escalation via iam:PassRole (mapped to MITRE ATT&CK T1078.004: Cloud Accounts and T1098: Account Manipulation). We analyzed how an adversary with restricted developer or DevOps access exploits an over-permissive iam:PassRole grant ("Resource": "*") to pass an administrative service role to a serverless compute service (AWS Lambda, EC2, AWS Glue, or CloudFormation). When invoked, the compute resource assumes the elevated role via the AWS Security Token Service (STS) and attaches the managed AdministratorAccess policy directly to the attacker's user, resulting in total cloud account takeover.

For cloud security architects, IAM engineers, and blue teams, defending enterprise AWS environments against iam:PassRole abuse exposes critical structural challenges unique to the AWS identity delegation model:

  • The Inherent Misunderstanding of PassRole: iam:PassRole is not an API that performs a standalone action; it is a permission evaluated when passing a role to an execution service. Developers and platform teams routinely configure iam:PassRole with wildcard resources (Resource: "*") because restricting ARNs requires anticipating every future application role name, inadvertently granting permission to pass high-privilege account roles.
  • The Inefficacy of Standard Perimeter & Network Defenses: Cloud control plane privilege escalations occur entirely over authenticated HTTPS requests to the AWS IAM and Lambda API endpoints (iam.amazonaws.com, lambda.amazonaws.com). Perimeter firewalls, VPC security groups, and Network Access Control Lists (NACLs) have zero visibility into internal IAM policy semantics or role delegation handshakes.
  • Ambient Compute Trust Policies: Many enterprise organizations create administrative roles (such as automated patching roles or cross-account deployment roles) whose trust policies allow broad assumption by lambda.amazonaws.com or ec2.amazonaws.com. If any low-privilege user in the account possesses unrestricted iam:PassRole, those administrative roles become immediate privilege escalation bridges.
  • The Additive Nature of IAM Policies: In AWS IAM, permissions are evaluated additively. If a developer creates a role and attaches policies without an administrative ceiling, the newly created role can assume privileges greater than the creator's own identity. Preventing this requires enforcing IAM Permission Boundaries.
Warning

An IAM policy that pairs iam:PassRole on wildcard resources ("*") with resource creation permissions (lambda:CreateFunction, ec2:RunInstances, or cloudformation:CreateStack) is functionally identical to granting full AdministratorAccess. Blue teams must strictly constrain iam:PassRole to designated role ARN paths and enforce iam:PassedToService condition keys.

⚔️ Exploitation Mechanics: For root-cause memory corruption analysis and attack flow, see our deep-dive: Deconstructing Breakdown.


Architecture Hardening: Multi-Layered IAM Defense-in-Depth#

Securing enterprise AWS environments against iam:PassRole privilege escalation demands a comprehensive four-tier defense-in-depth architecture: Strictly Scoped Resource ARNs and Condition Keys, Mandatory IAM Permission Boundaries, Organization-Wide Service Control Policies (SCPs), and Least-Privilege Service Trust Policies.

Defense Architecture Flowchart#

flowchart TD
    classDef client fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#f8fafc
    classDef gate fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#93c5fd
    classDef iam fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#6ee7b7
    classDef audit fill:#4c1d95,stroke:#8b5cf6,stroke-width:2px,color:#ddd6fe
    classDef drop fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fca5a5
    classDef pass fill:#065f46,stroke:#34d399,stroke-width:2px,color:#a7f3d0

    CallerReq[Developer / User Invokes API: lambda:CreateFunction --role ARN]:::client --> SCPCheck{Tier 1: Organization Service Control Policy Gate}:::gate

    SCPCheck -- Attempting to Pass Restricted Admin / Core Role --> DropSCP[Action: Deny by SCP Organization Rule]:::drop
    SCPCheck -- Complies with SCP Boundaries --> PassRolePolicy{Tier 2: Caller Identity PassRole Evaluation}:::gate

    PassRolePolicy -- Wildcard or Unscoped Role ARN Attempted --> DropUnscoped[Action: Deny PassRole on Unauthorized ARN]:::drop
    PassRolePolicy -- Role ARN Matches Designated App Path --> ConditionCheck{Tier 3: iam:PassedToService Condition Gate}:::iam

    ConditionCheck -- Service Does Not Match Configured Target --> DropService[Action: Deny Service Delegation Mismatch]:::drop
    ConditionCheck -- Target Service Matches lambda.amazonaws.com --> BoundaryCheck{Tier 4: Mandatory IAM Permission Boundary}:::iam

    BoundaryCheck -- Target Role Missing Permission Boundary Ceiling --> DropBoundary[Action: Deny by Boundary Enforcement Policy]:::drop
    BoundaryCheck -- Role Constrained by Boundary Ceiling --> AllowDelegation[AWS Control Plane Attaches Role to Lambda]:::pass

    AllowDelegation --> SafeExecution[Lambda Executes within Hardened Boundary Ceiling]:::pass

    DropSCP -.-> TelemetryStream[Tier 5: CloudTrail & GuardDuty Telemetry Stream]:::audit
    DropUnscoped -.-> TelemetryPipeline
    DropBoundary -.-> TelemetryPipeline
    TelemetryPipeline --> SOCAlert[SOC Incident Triage Triggered]:::pass

Layer 1: Strictly Scoping iam:PassRole with Resource ARNs and Condition Keys#

The most direct remediation for iam:PassRole abuse is eliminating wildcard resources and enforcing the iam:PassedToService condition key. This ensures that the caller can only pass specific, application-tier roles to explicitly approved AWS services.

Deploy the following least-privilege IAM policy template across developer roles:

JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowScopedPassRoleToLambdaOnly",
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/application-roles/*",
      "Condition": {
        "StringEquals": {
          "iam:PassedToService": "lambda.amazonaws.com"
        }
      }
    },
    {
      "Sid": "AllowLambdaManagementWithinAppNamespace",
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:UpdateFunctionCode",
        "lambda:UpdateFunctionConfiguration",
        "lambda:InvokeFunction"
      ],
      "Resource": "arn:aws:lambda:*:123456789012:function:app-*"
    }
  ]
}

By enforcing arn:aws:iam::123456789012:role/application-roles/* and "iam:PassedToService": "lambda.amazonaws.com":

  • The caller cannot pass any role outside the /application-roles/ IAM path (preventing delegation of account-level administrative roles).
  • The caller cannot pass the role to unintended compute services (such as EC2 or Glue).

Layer 2: Mandatory IAM Permission Boundaries#

An IAM Permission Boundary is an advanced authorization control that sets the maximum permissions an identity-based policy can grant to an IAM entity. Even if a role has the AdministratorAccess policy attached, its effective permissions can never exceed the ceiling defined by its permission boundary.

To prevent developers from creating roles with elevated privileges or passing unconstrained roles, enforce a policy that requires all created or passed roles to have a designated permission boundary attached:

JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnforcePermissionBoundaryOnRoleCreation",
      "Effect": "Allow",
      "Action": [
        "iam:CreateRole",
        "iam:AttachRolePolicy",
        "iam:PutRolePolicy"
      ],
      "Resource": "arn:aws:iam::123456789012:role/application-roles/*",
      "Condition": {
        "StringEquals": {
          "iam:PermissionsBoundary": "arn:aws:iam::123456789012:policy/DeveloperBoundaryPolicy"
        }
      }
    },
    {
      "Sid": "DenyBoundaryTampering",
      "Effect": "Deny",
      "Action": [
        "iam:DeleteRolePermissionsBoundary",
        "iam:DeletePolicyVersion",
        "iam:CreatePolicyVersion"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:policy/DeveloperBoundaryPolicy",
        "arn:aws:iam::123456789012:role/application-roles/*"
      ]
    }
  ]
}

Layer 3: Organization-Wide Service Control Policies (SCPs)#

At the AWS Organizations management root, deploy Service Control Policies (SCPs) to prevent any member account principal from passing administrative roles or tampering with central security controls:

JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyPassingAdminAndSecurityRoles",
      "Effect": "Deny",
      "Action": "iam:PassRole",
      "Resource": [
        "arn:aws:iam::*:role/*Admin*",
        "arn:aws:iam::*:role/*Administrator*",
        "arn:aws:iam::*:role/*Security*",
        "arn:aws:iam::*:role/*OrganizationAccountAccessRole*"
      ],
      "Condition": {
        "ArnNotLike": {
          "aws:PrincipalARN": [
            "arn:aws:iam::*:role/CentralSecurityAdminRole",
            "arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*"
          ]
        }
      }
    }
  ]
}

Layer 4: Hardening Service Trust Policies (AssumeRolePolicyDocument)#

A role cannot be passed to a service unless its trust policy explicitly permits that service to assume it. Perform a fleet-wide audit of all role trust policies in your AWS account:

  • Remove lambda.amazonaws.com, ec2.amazonaws.com, or other service principals from any role containing AdministratorAccess or broad IAM manipulation permissions.
  • If an administrative role must be assumed by automation, restrict assumption to dedicated cross-account CI/CD role ARNs or require MFA ("aws:MultiFactorAuthPresent": "true").

Production Detection Queries: Sigma Rule, CloudTrail & EventBridge#

Detecting iam:PassRole abuse requires monitoring CloudTrail for role delegation events combined with resource creation, as well as alerting on anomalous IAM privilege modifications.

1. Production Sigma Rule: Suspicious iam:PassRole to AWS Compute Service#

The following production-validated Sigma rule monitors AWS CloudTrail management events, alerting when an IAM user passes a role containing administrative naming patterns to a compute service:

YAML
title: AWS IAM PassRole to Privileged Compute Service
id: 5a91f82c-4c3a-49a1-b841-8e9c9e012078
status: production
description: |
    Detects instances where an IAM user passes an administrative or privileged IAM role 
    to an AWS compute resource (such as Lambda, EC2, Glue, or CloudFormation) via iam:PassRole, 
    indicative of cloud privilege escalation (MITRE T1078.004).
references:
    - https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/
    - https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html

tags:
    - attack.privilege_escalation
    - attack.persistence
    - attack.t1078.004
    - attack.t1098
logsource:
    service: cloudtrail
    product: aws
detection:
    selection_compute_events:
        eventName:
            - 'CreateFunction20150331' # Lambda CreateFunction
            - 'UpdateFunctionCode20150331'
            - 'RunInstances'
            - 'CreateDevEndpoint'
            - 'CreateStack'
            - 'CreateProject' # CodeBuild
    selection_privileged_roles:
        requestParameters.role|contains:
            - 'admin'
            - 'Admin'
            - 'FullAccess'
            - 'PowerUser'
            - 'OrganizationAccountAccessRole'
    filter_approved_automation:
        userIdentity.type: 'AssumedRole'
        userIdentity.sessionContext.sessionIssuer.userName|startswith:
            - 'AWSServiceRole'
            - 'TerraformPipeline'
            - 'AWSControlTower'
    condition: selection_compute_events and selection_privileged_roles and not filter_approved_automation
fields:
    - eventTime
    - userIdentity.userName
    - eventName
    - requestParameters.role
    - requestParameters.functionName
    - sourceIPAddress
falsepositives:
    - Legitimate infrastructure-as-code automation pipelines deploying approved services.
level: high

2. Automated Remediation via Amazon EventBridge & Lambda#

Deploy an EventBridge rule that detects unauthorized AttachUserPolicy calls granting AdministratorAccess and immediately revokes the policy:

JSON
{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["AttachUserPolicy", "AttachRolePolicy"],
    "requestParameters": {
      "policyArn": ["arn:aws:iam::aws:policy/AdministratorAccess"]
    }
  }
}

When triggered, an automated security Lambda function inspects the caller; if the caller is not the designated root deployment pipeline, it detaches the policy immediately, deactivates the caller's access keys, and emits a high-priority alert to the SOC.


Enterprise Mitigation Matrix: Workarounds, Hotfixes & Architecture#

When prioritizing defensive engineering against iam:PassRole privilege escalation, cloud security teams must balance operational agility against isolation boundaries:

Remediation Strategy Implementation Effort Blast Radius & Operational Risk Detection & Prevention Efficacy Performance Overhead Architectural Longevity
Workaround: Eliminate Wildcard Resources on PassRole 2 - 4 Hours
(Audit all identity policies and replace Resource: "*" with specific ARNs)
Low - Moderate
May require updating CI/CD policies that dynamically provision role names.
High (85%)
Blocks passing unapproved roles; restricts escalation targets.
Zero
Native IAM policy evaluation.
Tactical Baseline
Immediate mitigation while designing permission boundaries.
Operational Control: Enforce iam:PassedToService Condition Key 1 - 2 Days
(Attach iam:PassedToService condition to all PassRole statements)
Low
Ensures roles meant for Lambda cannot be passed to EC2 or Glue.
High (90%)
Eliminates cross-service confused deputy exploitation paths.
Zero
Native IAM policy evaluation.
Core Policy Standard
Essential CIS AWS Benchmark compliance requirement.
Architecture Fix: Mandatory IAM Permission Boundaries 1 - 2 Weeks
(Deploy boundary policies across all developer and service role pipelines)
Moderate
Requires updating role creation scripts to include boundary parameters.
Absolute Against Escalation (100%)
Enforces an immutable permission ceiling regardless of attached policies.
Zero
Native IAM policy evaluation.
Mandatory Standard
Permanently neutralizes role-based privilege escalation.
Organization Fix: Service Control Policies (SCPs) & Automated IR 2 - 4 Weeks
(Deploy organization-wide SCPs blocking admin role delegation)
Substantial
Requires testing across non-production accounts to avoid deployment drops.
Comprehensive (100%)
Enforces immutable organizational boundaries across all AWS accounts.
Zero
AWS Organizations control plane.
Permanent State
Zero-trust cloud architecture fully immune to PassRole takeover.
Important

Merely restricting iam:PassRole on IAM Users is insufficient if developers possess permissions to create or modify IAM roles (iam:CreateRole, iam:PutRolePolicy). A developer with iam:CreateRole can create a brand new role with administrative privileges unless restrained by an IAM Permission Boundary. Both controls must be deployed in tandem.


Incident Response & Verification Playbook: PassRole Escalation Triage#

If unauthorized iam:PassRole usage or an anomalous privilege escalation event is detected in your AWS account, execute the following four-phase incident response playbook immediately:

flowchart TD
    classDef alert fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fca5a5
    classDef check fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fef3c7
    classDef triage fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#93c5fd
    classDef clean fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#6ee7b7

    Triage[Phase 1: CloudTrail Triage & Session Audit]:::triage --> CorrelateLogs{Check CloudTrail for PassRole + CreateFunction Calls}:::check

    CorrelateLogs -- Unauthorized Role Passed to Compute Service --> IsolateCaller[Phase 2: Immediate Containment & Principal Quarantine]:::alert
    CorrelateLogs -- Clean CloudTrail Activity --> CheckGuardDuty{Check GuardDuty for PrivilegeEscalation Alerts}:::check

    CheckGuardDuty -- Anomalous API Calls Detected --> IsolateCaller
    CheckGuardDuty -- False Positive Confirmed --> CloseIncident[Close Incident as Clean / Low Risk]:::clean

    IsolateCaller --> DetachPolicies[Phase 3: Detach Unauthorized Admin Policies]:::alert
    DetachPolicies --> DeleteBackdoors[Delete Rogue Lambda Functions & EC2 Instances]:::alert
    DeleteBackdoors --> RevokeSTSTokens[Revoke Active STS Temporary Credentials]:::alert

    RevokeSTSTokens --> Phase4[Phase 4: Post-Remediation Hardening & Verification]:::clean

Phase 1: Live Triage & Forensic CloudTrail Audit#

  1. Query CloudTrail for Recent Compute Resource Creations: Inspect CloudTrail logs over the past 24 hours for instances where non-administrative users invoked compute creation APIs passing IAM roles:
BASH
# Search CloudTrail for Lambda CreateFunction events
aws cloudtrail lookup-events     --lookup-attributes AttributeKey=EventName,AttributeValue=CreateFunction20150331     --start-time $(date -u -d '24 hours ago' +%s)     --query "Events[].[EventTime,Username,Resources[0].ResourceName]"     --output table
  1. Inspect Attached IAM Policies on the Calling Principal: Verify whether the user has been recently granted administrative policies:
BASH
# Inspect policies attached to suspect user
aws iam list-attached-user-policies --user-name <SUSPECT_USER>
aws iam list-user-policies --user-name <SUSPECT_USER>

Phase 2: Immediate Containment & Principal Quarantine#

  1. Quarantine the Compromised Calling Principal: Immediately attach an explicit inline Deny policy to the suspected IAM user or role to terminate all access:
BASH
# Attach emergency quarantine policy denying all actions
aws iam put-user-policy     --user-name <SUSPECT_USER>     --policy-name EmergencyQuarantine     --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*"}]}'

# Deactivate all active access keys for the user
for key in $(aws iam list-access-keys --user-name <SUSPECT_USER> --query "AccessKeyMetadata[].AccessKeyId" --output text); do
    aws iam update-access-key --user-name <SUSPECT_USER> --access-key-id $key --status Inactive
done
  1. Revoke Active Temporary STS Sessions: Invalidate any temporary credentials generated by the assumed role prior to containment:
BASH
# Invalidate temporary STS credentials issued for the compromised role
aws iam put-role-policy     --role-name <COMPROMISED_ROLE_NAME>     --policy-name RevokeOldSessions     --policy-document "{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*","Condition":{"DateLessThan":{"aws:TokenIssueTime":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}}}]}"

Phase 3: Eradication & Artifact Clean-Up#

  1. Delete Rogue Compute Resources: Delete the malicious Lambda function, terminate the EC2 instance, or delete the CloudFormation stack created during exploitation:
BASH
# Delete the malicious Lambda function
aws lambda delete-function --function-name <ROGUE_FUNCTION_NAME> --region <REGION>
  1. Detach Unauthorized IAM Policies: Remove any elevated policies attached by the exploit:
BASH
# Detach unauthorized AdministratorAccess policy
aws iam detach-user-policy     --user-name <SUSPECT_USER>     --policy-arn "arn:aws:iam::aws:policy/AdministratorAccess"

Phase 4: Post-Remediation Verification & Hardening Checklist#

Before concluding incident response and restoring development operations:

  • Verify that all access keys for the compromised user have been deactivated and deleted.
  • Confirm that Resource: "*" on iam:PassRole has been eliminated from all identity policies.
  • Verify that the iam:PassedToService condition key is enforced on all active PassRole statements.
  • Confirm that IAM Permission Boundaries are attached to all developer and automation roles.
  • Deploy the production Sigma rule 5a91f82c-4c3a-49a1-b841-8e9c9e012078 into your cloud SIEM.
  • Verify that the Amazon EventBridge automated policy detachment rule is active across the organization.

Executive Takeaway Table#

Attack Vector / Phase Forensic Detection Signal Primary Defensive Mitigation
IAM Policy Enumeration Spike in iam:ListRoles and iam:GetUserPolicy API calls in CloudTrail. Enforce least-privilege IAM read policies; alert on rapid IAM discovery.
Unscoped PassRole Delegation IAM policies contain Action: iam:PassRole with wildcard "Resource": "*". Scope Resource strictly to /application-roles/*; enforce iam:PassedToService.
Malicious Function Creation CloudTrail event CreateFunction20150331 passing administrative role ARN. Enforce mandatory IAM Permission Boundaries on all created roles.
Compute Privilege Escalation CloudTrail event AttachUserPolicy originating from internal Lambda IP address. Deploy Service Control Policies (SCPs) denying admin role delegation across accounts.
Account-Wide Persistence Non-admin user account assigned AdministratorAccess or custom admin policies. Deploy Amazon EventBridge automated remediation to revoke unauthorized policy attachments.

Authoritative References#

  1. AWS Identity and Access Management Documentation: Granting a User Permissions to Pass a Role to an AWS Service — AWS Documentation
  2. AWS Security Guidance: Permissions boundaries for IAM entities — AWS Documentation
  3. Rhino Security Labs Research: AWS IAM Privilege Escalation: Methods and Mitigation by Spencer Gietzen — Rhino Security Labs
  4. Bishop Fox Research: Investigating Privilege Escalation Methods in AWS — Bishop Fox Cybersecurity
  5. MITRE ATT&CK Framework: Technique T1078.004: Valid Accounts - Cloud Accounts — MITRE ATT&CK

Comments