aws-emr-exposes-instance-profile-cred

Every EC2 node in an EMR cluster exposes the instance profile (JobFlowRole) credentials via the EC2 Instance Metadata Service (IMDS); any code running on the cluster can retrieve them.

derived aws emits ExposesCredential

match

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

{'cluster': None} ExecutesAs {'role': None}

where

node_type(?cluster) == AnalyticsService ?cluster provider_type == AWS::EMR::Cluster

emit

source typeAnalyticsService
target typeIdentity
source?cluster
target?role
conditionsservice_state
state logicACTIVE when the cluster is in RUNNING/WAITING state. CONDITIONAL(condition_expression) when IMDSv2 with HttpPutResponseHopLimit=1 is enforced on all cluster instances (reduces but does not eliminate risk — hop-limit enforcement is per-instance and does not apply retroactively). Do NOT mark BLOCKED solely on IMDSv2: containerized or privileged steps may still bypass the hop-limit; analysts should verify instance metadata options explicitly.

Narrative

EMR cluster {cluster.name} exposes the credentials of its instance profile role {role.name} via IMDS (http://169.254.169.254) on every EC2 node; any code executing on the cluster (including submitted steps) can retrieve those credentials without additional permissions.

Raw rule rules/derived/aws/emr.yaml

id: aws-emr-exposes-instance-profile-cred
emits: ExposesCredential
description: Every EC2 node in an EMR cluster exposes the instance profile (JobFlowRole) credentials via
  the EC2 Instance Metadata Service (IMDS); any code running on the cluster can retrieve them.
match:
- - cluster: null
  - ExecutesAs
  - role: null
where:
- node_type(?cluster) == AnalyticsService
- ?cluster provider_type == AWS::EMR::Cluster
emit:
  source_type: AnalyticsService
  target_type: Identity
  source: ?cluster
  target: ?role
  permissions: []
  conditions:
  - service_state
  state_logic: "ACTIVE when the cluster is in RUNNING/WAITING state. CONDITIONAL(condition_expression)\
    \ when IMDSv2 with HttpPutResponseHopLimit=1 is enforced on all cluster instances (reduces but does\
    \ not eliminate risk \u2014 hop-limit enforcement is per-instance and does not apply retroactively).\
    \ Do NOT mark BLOCKED solely on IMDSv2: containerized or privileged steps may still bypass the hop-limit;\
    \ analysts should verify instance metadata options explicitly."
  derived_from:
  - <ExecutesAs(aws-emr-executes-as-instance-profile) edge_id>
  false_positive_note: "This is a structural fact: the IMDS credential-exposure is inherent to EMR EC2\
    \ clusters. It is not an escalation by itself \u2014 it becomes an attack step when combined with\
    \ a CanModifyCode/AddJobFlowSteps edge (code gets on the cluster and reads IMDS). Do not BLOCK solely\
    \ on IMDSv2 \u2014 downgrade to CONDITIONAL(condition_expression) only when IMDSv2 hop-limit=1 is\
    \ confirmed on all nodes. EMR Serverless does NOT use IMDS; this rule does not apply to Serverless\
    \ job runs."
  narrative: EMR cluster {cluster.name} exposes the credentials of its instance profile role {role.name}
    via IMDS (http://169.254.169.254) on every EC2 node; any code executing on the cluster (including
    submitted steps) can retrieve those credentials without additional permissions.
move · open · esc close