aws-opsworks-update-stack-cookbook-supply-chain
opsworks:UpdateStack can redirect the custom cookbook source to an attacker-controlled repo, making all future cookbook deployments run attacker code as the instance profile role.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?stack) ==
ApplicationPlatform
?stack.provider_type == 'AWS::OpsWorks::Stack'
?principal has effective opsworks:UpdateStack on ?stack
?stack has at least one ONLINE instance
emit
| source type | Identity |
|---|---|
| target type | VirtualMachine |
| source | ?principal |
| target | <OpsWorks-managed EC2 instances in ?stack> |
| permissions | opsworks:UpdateStack |
| conditions | service_state trigger_exists |
| state logic | ACTIVE when at least one instance is ONLINE and a deployment can be triggered (attacker has opsworks:CreateDeployment or a scheduled lifecycle event exists). CONDITIONAL(service_state) when all instances are stopped. CONDITIONAL(trigger_exists) when no deployment trigger path is established and the attacker cannot issue update_custom_cookbooks themselves. Persistent: the cookbook URL change survives restarts and affects every future deployment. |
Narrative
{principal.name} can call opsworks:UpdateStack to redirect {stack.name}'s custom cookbook source to an attacker-controlled repository. The next update_custom_cookbooks deployment pulls the attacker's Chef code onto all instances; subsequent execute_recipes runs it as the instance profile role.
Raw rule rules/derived/aws/opsworks.yaml
id: aws-opsworks-update-stack-cookbook-supply-chain
emits: CanModifyCode
description: opsworks:UpdateStack can redirect the custom cookbook source to an attacker-controlled repo,
making all future cookbook deployments run attacker code as the instance profile role.
match:
- - principal: null
- HasPermission
- stack: null
where:
- node_type(?stack) == ApplicationPlatform
- ?stack.provider_type == 'AWS::OpsWorks::Stack'
- ?principal has effective opsworks:UpdateStack on ?stack
- ?stack has at least one ONLINE instance
emit:
source_type: Identity
target_type: VirtualMachine
source: ?principal
target: <OpsWorks-managed EC2 instances in ?stack>
permissions:
- opsworks:UpdateStack
conditions:
- service_state
- trigger_exists
state_logic: 'ACTIVE when at least one instance is ONLINE and a deployment can be triggered (attacker
has opsworks:CreateDeployment or a scheduled lifecycle event exists). CONDITIONAL(service_state) when
all instances are stopped. CONDITIONAL(trigger_exists) when no deployment trigger path is established
and the attacker cannot issue update_custom_cookbooks themselves. Persistent: the cookbook URL change
survives restarts and affects every future deployment.'
confidence: 0.85
derived_from:
- ?principal HasPermission ?stack (opsworks:UpdateStack)
- cicd-chains cicd-modify-buildspec-executes-as (cited, not re-derived)
false_positive_note: "opsworks:UpdateStack in a single API call can both set UseCustomCookbooks=true\
\ AND set the cookbook source URL; therefore the 'custom cookbooks not enabled' check does NOT block\
\ this edge \u2014 the attacker's UpdateStack call enables it. Confidence 0.85 (slightly lower than\
\ CreateDeployment/rule 1) because a follow-on update_custom_cookbooks deployment is needed to pull\
\ the new cookbooks onto the instances; if the attacker cannot also trigger a deployment they must\
\ wait for a natural lifecycle event (CONDITIONAL). Do not emit for stacks with zero instances. This\
\ rule targets VirtualMachine (execution surface) to align with explicit aws-opsworks-can-modify-code-create-deployment\
\ target and enable cicd-chains deduplication on (CanModifyCode, principal, instance)."
narrative: '{principal.name} can call opsworks:UpdateStack to redirect {stack.name}''s custom cookbook
source to an attacker-controlled repository. The next update_custom_cookbooks deployment pulls the
attacker''s Chef code onto all instances; subsequent execute_recipes runs it as the instance profile
role.'