aws-ec2-run-instances-as-role

RunInstances + PassRole -> launch an instance running as a chosen role, then read IMDS.

derived aws emits CanCreateWorkloadAs

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanPassIdentity {'role': None}

where

?principal has EFFECTIVE ec2:RunInstances (+ iam:AddRoleToInstanceProfile / iam:CreateInstanceProfile if no profile exists) ?role trust policy allows Principal Service ec2.amazonaws.com iam:PassRole iam:PassedToService condition (if any) includes ec2.amazonaws.com

emit

source typeIdentity
target typeIdentity
source<principal>
target<IAM role>
permissionsiam:PassRole ec2:RunInstances iam:AddRoleToInstanceProfile
conditionsrole_compatibility iam_permission condition_expression
state logicACTIVE if role trusts ec2.amazonaws.com and PassedToService includes ec2 else POTENTIAL(role_compatibility)

Narrative

{principal.name} can pass {role.name} to EC2 and run a new instance (iam:PassRole + ec2:RunInstances), executing code as {role.name} and reading its credentials from IMDS.

Raw rule rules/derived/aws/ec2.yaml

id: aws-ec2-run-instances-as-role
emits: CanCreateWorkloadAs
description: RunInstances + PassRole -> launch an instance running as a chosen role, then read IMDS.
match:
- - principal: null
  - CanPassIdentity
  - role: null
where:
- ?principal has EFFECTIVE ec2:RunInstances (+ iam:AddRoleToInstanceProfile / iam:CreateInstanceProfile
  if no profile exists)
- ?role trust policy allows Principal Service ec2.amazonaws.com
- iam:PassRole iam:PassedToService condition (if any) includes ec2.amazonaws.com
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <IAM role>
  permissions:
  - iam:PassRole
  - ec2:RunInstances
  - iam:AddRoleToInstanceProfile
  conditions:
  - role_compatibility
  - iam_permission
  - condition_expression
  escalation: Launch an attacker-controlled instance bound to a privileged role; UserData runs as root
    and IMDS vends the role's STS credentials.
  state_logic: ACTIVE if role trusts ec2.amazonaws.com and PassedToService includes ec2 else POTENTIAL(role_compatibility)
  false_positive_note: Only ACTIVE when the role trust allows ec2.amazonaws.com AND iam:PassRole is not
    scoped away from ec2 via iam:PassedToService. A role passable only to lambda/ecs does NOT yield EC2
    execution.
  narrative: '{principal.name} can pass {role.name} to EC2 and run a new instance (iam:PassRole + ec2:RunInstances),
    executing code as {role.name} and reading its credentials from IMDS.'
move · open · esc close