aws-emr-on-eks-execute-as

Submit an EMR on EKS job run with attacker-controlled application code and a passed privileged execution role via emr-containers:StartJobRun + iam:PassRole.

derived aws emits CanExecuteAs

match

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

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

where

node_type(?cluster) == AnalyticsService ?cluster provider_type == AWS::EMRContainers::VirtualCluster CanModifyCode here is derived from emr-containers:StartJobRun (EMR on EKS job code submission) CanPassIdentity here is aws-emr-on-eks-pass-job-role (PassRole for emr-containers.amazonaws.com)

emit

source typeIdentity
target typeIdentity
source?principal
target?role
permissionsemr-containers:StartJobRun iam:PassRole
conditionsiam_permission role_compatibility
state logicACTIVE when principal has EFFECTIVE emr-containers:StartJobRun on the virtual cluster AND iam:PassRole for ?role (PassedToService = emr-containers.amazonaws.com) AND the role's trust allows the EKS OIDC provider. CONDITIONAL(role_compatibility) when PassedToService or IRSA binding is unknown. BLOCKED if SCP or permission boundary denies either action.

Narrative

{principal.name} can submit an EMR on EKS job run with attacker-chosen application code (emr-containers:StartJobRun) and pass privileged execution role {role.name} (iam:PassRole); the Spark/Hive job executes arbitrary code as {role.name} via the EKS pod identity/OIDC token exchange.

Raw rule rules/derived/aws/emr.yaml

id: aws-emr-on-eks-execute-as
emits: CanExecuteAs
description: Submit an EMR on EKS job run with attacker-controlled application code and a passed privileged
  execution role via emr-containers:StartJobRun + iam:PassRole.
match:
- - principal: null
  - CanModifyCode
  - cluster: null
- - principal: null
  - CanPassIdentity
  - role: null
where:
- node_type(?cluster) == AnalyticsService
- ?cluster provider_type == AWS::EMRContainers::VirtualCluster
- CanModifyCode here is derived from emr-containers:StartJobRun (EMR on EKS job code submission)
- CanPassIdentity here is aws-emr-on-eks-pass-job-role (PassRole for emr-containers.amazonaws.com)
emit:
  source_type: Identity
  target_type: Identity
  source: ?principal
  target: ?role
  permissions:
  - emr-containers:StartJobRun
  - iam:PassRole
  conditions:
  - iam_permission
  - role_compatibility
  state_logic: ACTIVE when principal has EFFECTIVE emr-containers:StartJobRun on the virtual cluster AND
    iam:PassRole for ?role (PassedToService = emr-containers.amazonaws.com) AND the role's trust allows
    the EKS OIDC provider. CONDITIONAL(role_compatibility) when PassedToService or IRSA binding is unknown.
    BLOCKED if SCP or permission boundary denies either action.
  confidence: min(contributing_confidences) * 0.95
  derived_from:
  - <CanModifyCode(emr-containers:StartJobRun) edge_id>
  - <CanPassIdentity(aws-emr-on-eks-pass-job-role) edge_id>
  false_positive_note: "PassRole is ALWAYS required for EMR on EKS. The role's trust must allow the EKS\
    \ cluster's OIDC provider (IRSA); without this, the pod cannot assume the role. Honor emr-containers.amazonaws.com\
    \ in the PassedToService condition. Escalation roll-up is can-control escalate-via-execute-as \u2014\
    \ CITE, do not re-derive."
  narrative: '{principal.name} can submit an EMR on EKS job run with attacker-chosen application code
    (emr-containers:StartJobRun) and pass privileged execution role {role.name} (iam:PassRole); the Spark/Hive
    job executes arbitrary code as {role.name} via the EKS pod identity/OIDC token exchange.'
move · open · esc close