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.
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 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 — 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.'