aws-codedeploy-trigger-executes-as-service-role
Trigger a deployment to execute orchestration-plane actions as the deployment group's service role - requires a run path.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanModifyCode {'deploygroup': None}
{'deploygroup': None} ExecutesAs {'servicerole': None}
where
node_type(?deploygroup) ==
AutomationService
?deploygroup.provider_type == AWS::CodeDeploy::DeploymentGroup
?servicerole.provider_type == AWS::IAM::Role
?servicerole.privilege_level > ?principal.privilege_level
optional
Present → upgrade the emitted state; absent → downgrade (not a hard requirement).
{'principal': None}
CanTrigger {'deploygroup': None}
emit
| source type | Identity |
|---|---|
| target type | Role |
| source | ?principal |
| target | ?servicerole |
| permissions | codedeploy:CreateDeployment |
| conditions | iam_permission service_state trigger_exists |
| state logic | ACTIVE when ?principal has effective codedeploy:CreateDeployment on ?deploygroup AND ?deploygroup is ACTIVE (not paused/stopped) AND ?servicerole is more privileged than ?principal AND a deployment trigger exists (matched(optional[0]) or an armed trigger like CodePipeline / webhook / schedule). CONDITIONAL (trigger_exists) when the principal can modify the group but cannot trigger a deployment — the service role is only exercised when a deployment runs, and without a trigger mechanism, the modification does not yield execution. Only emit when privilege(?servicerole) > privilege(?principal) — the service role credentials are exercised by the CodeDeploy service process, not directly by attacker code running on instances. Strictly weaker than the instance-role RCE path because it is orchestration-plane, not arbitrary-code execution. Inherits weakest of CanModifyCode and ExecutesAs contributors. |
Narrative
{principal.name} can trigger a CodeDeploy deployment (codedeploy:CreateDeployment) that exercises the service role {servicerole.name}; this lets the principal indirectly leverage {servicerole.name}'s orchestration-plane permissions (ELB deregister, ASG, EC2 tag/describe) through the CodeDeploy control plane.
Raw rule rules/derived/aws/codedeploy.yaml
id: aws-codedeploy-trigger-executes-as-service-role
emits: CanExecuteAs
description: "Trigger a deployment to execute orchestration-plane actions as the deployment group's service\
\ role \u2014 requires a run path."
match:
- - principal: null
- CanModifyCode
- deploygroup: null
- - deploygroup: null
- ExecutesAs
- servicerole: null
where:
- node_type(?deploygroup) == AutomationService
- ?deploygroup.provider_type == AWS::CodeDeploy::DeploymentGroup
- ?servicerole.provider_type == AWS::IAM::Role
- ?servicerole.privilege_level > ?principal.privilege_level
optional:
- - principal: null
- CanTrigger
- deploygroup: null
emit:
source_type: Identity
target_type: Role
source: ?principal
target: ?servicerole
permissions:
- codedeploy:CreateDeployment
conditions:
- iam_permission
- service_state
- trigger_exists
state_logic: "ACTIVE when ?principal has effective codedeploy:CreateDeployment on ?deploygroup AND ?deploygroup\
\ is ACTIVE (not paused/stopped) AND ?servicerole is more privileged than ?principal AND a deployment\
\ trigger exists (matched(optional[0]) or an armed trigger like CodePipeline / webhook / schedule).\
\ CONDITIONAL (trigger_exists) when the principal can modify the group but cannot trigger a deployment\
\ \u2014 the service role is only exercised when a deployment runs, and without a trigger mechanism,\
\ the modification does not yield execution. Only emit when privilege(?servicerole) > privilege(?principal)\
\ \u2014 the service role credentials are exercised by the CodeDeploy service process, not directly\
\ by attacker code running on instances. Strictly weaker than the instance-role RCE path because it\
\ is orchestration-plane, not arbitrary-code execution. Inherits weakest of CanModifyCode and ExecutesAs\
\ contributors."
confidence: 0.75
derived_from:
- ?principal CanModifyCode ?deploygroup
- ?deploygroup ExecutesAs ?servicerole
false_positive_note: "The CodeDeploy service role is exercised by the CodeDeploy service plane, not\
\ by attacker code running on instances. The attacker cannot call AWS APIs as the service role directly;\
\ they can only observe its side effects (ELB deregister/ register, ASG lifecycle hooks, EC2 tag).\
\ Emit at confidence 0.75 to reflect this indirect control. If the service role has only narrow permissions\
\ (ELB deregister/register, EC2 describe), it may not be a meaningful escalation \u2014 only emit\
\ when privilege(?servicerole) > privilege(?principal). A deployment trigger (manual creation via\
\ codedeploy:CreateDeployment, or an armed trigger from CodePipeline / webhook / schedule) must exist\
\ for the service role to be exercised. Without a trigger, downgrade to CONDITIONAL(trigger_exists).\
\ Cite can-execute-as for the escalation roll-up; do not re-derive CanEscalateTo here."
narrative: '{principal.name} can trigger a CodeDeploy deployment (codedeploy:CreateDeployment) that
exercises the service role {servicerole.name}; this lets the principal indirectly leverage {servicerole.name}''s
orchestration-plane permissions (ELB deregister, ASG, EC2 tag/describe) through the CodeDeploy control
plane.'