aws-imagebuilder-swap-instance-profile-executes-as

Replace the infrastructure configuration's instance profile with a higher-privilege IAM role (UpdateInfrastructureConfiguration + iam:PassRole), then trigger a build to execute as that role.

derived aws emits CanExecuteAs

match

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

{'principal': None} CanModifyConfiguration {'infra_config': None} {'principal': None} CanPassIdentity {'role': None} {'pipeline': None} CanModifyConfiguration {'infra_config': None}

where

node_type(?infra_config) == BuildWorker ?infra_config.provider_type == 'AWS::ImageBuilder::InfrastructureConfiguration' ?role trust policy allows ec2.amazonaws.com (or trust is unknown)

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

{'principal': None} CanTrigger {'pipeline': None}

emit

source typeIdentity
target typeMachineIdentity
source?principal
target?role
permissionsimagebuilder:UpdateInfrastructureConfiguration iam:PassRole imagebuilder:StartImagePipelineExecution?
conditionsrole_compatibility run_path
state logicACTIVE when (a) the role trust policy permits ec2.amazonaws.com (iam:PassedToService for ec2.amazonaws.com or no PassedToService condition, and trust allows it), AND (b) a run path exists (attacker can trigger the pipeline or a schedule fires). CONDITIONAL(role_compatibility) when the role trust policy does not explicitly allow ec2.amazonaws.com or is unknown — the attach may fail at build time. CONDITIONAL(run_path) when role_compatibility is satisfied but no trigger/schedule exists. POTENTIAL when both conditions are unresolved. BLOCKED when an SCP or permission boundary denies imagebuilder:UpdateInfrastructureConfiguration or iam:PassRole on the role's ARN.

Narrative

{principal.name} can replace the instance profile in {infra_config.name} (imagebuilder:UpdateInfrastructureConfiguration) with {role.name} (iam:PassRole), then trigger a build on any pipeline using that infra config. The build instance runs as {role.name}, exposing its credentials to attacker-injected component steps.

Raw rule rules/derived/aws/imagebuilder.yaml

id: aws-imagebuilder-swap-instance-profile-executes-as
emits: CanExecuteAs
description: Replace the infrastructure configuration's instance profile with a higher-privilege IAM role
  (UpdateInfrastructureConfiguration + iam:PassRole), then trigger a build to execute as that role.
match:
- - principal: null
  - CanModifyConfiguration
  - infra_config: null
- - principal: null
  - CanPassIdentity
  - role: null
- - pipeline: null
  - CanModifyConfiguration
  - infra_config: null
where:
- node_type(?infra_config) == BuildWorker
- ?infra_config.provider_type == 'AWS::ImageBuilder::InfrastructureConfiguration'
- ?role trust policy allows ec2.amazonaws.com (or trust is unknown)
optional:
- - principal: null
  - CanTrigger
  - pipeline: null
emit:
  source_type: Identity
  target_type: MachineIdentity
  source: ?principal
  target: ?role
  permissions:
  - imagebuilder:UpdateInfrastructureConfiguration
  - iam:PassRole
  - imagebuilder:StartImagePipelineExecution?
  conditions:
  - role_compatibility
  - run_path
  state_logic: "ACTIVE when (a) the role trust policy permits ec2.amazonaws.com (iam:PassedToService for\
    \ ec2.amazonaws.com or no PassedToService condition, and trust allows it), AND (b) a run path exists\
    \ (attacker can trigger the pipeline or a schedule fires). CONDITIONAL(role_compatibility) when the\
    \ role trust policy does not explicitly allow ec2.amazonaws.com or is unknown \u2014 the attach may\
    \ fail at build time. CONDITIONAL(run_path) when role_compatibility is satisfied but no trigger/schedule\
    \ exists. POTENTIAL when both conditions are unresolved. BLOCKED when an SCP or permission boundary\
    \ denies imagebuilder:UpdateInfrastructureConfiguration or iam:PassRole on the role's ARN."
  confidence: min(contributing_confidences) * 0.90
  derived_from:
  - ?principal CanModifyConfiguration ?infra_config (imagebuilder:UpdateInfrastructureConfiguration)
  - ?principal CanPassIdentity ?role (iam:PassRole)
  - ?principal CanTrigger ?pipeline? (imagebuilder:StartImagePipelineExecution)
  - can-execute-as execute-as-via-config-identity-swap (cited, deduped)
  false_positive_note: "The swapped role MUST trust ec2.amazonaws.com for the instance profile assignment\
    \ to succeed \u2014 Image Builder launches an EC2 instance and the IAM service validates the role's\
    \ trust policy. A role trusting only lambda.amazonaws.com or ecs-tasks.amazonaws.com cannot be used\
    \ here -> POTENTIAL(role_compatibility) until trust is confirmed. iam:PassedToService is not enforced\
    \ by imagebuilder natively, but the role's trust policy IS checked by IAM when EC2 calls AssumeRole\
    \ for the instance profile. Also confirm the attacker can reach a pipeline that uses this infra config\
    \ (pipeline ref check in where clause). Dedupes with can-execute-as execute-as-via-config-identity-swap\
    \ on (CanExecuteAs, ?principal, ?role) \u2014 emit once."
  narrative: '{principal.name} can replace the instance profile in {infra_config.name} (imagebuilder:UpdateInfrastructureConfiguration)
    with {role.name} (iam:PassRole), then trigger a build on any pipeline using that infra config. The
    build instance runs as {role.name}, exposing its credentials to attacker-injected component steps.'
move · open · esc close