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.

derived aws emits CanModifyCode

match

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

{'principal': None} HasPermission {'stack': None}

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 typeIdentity
target typeVirtualMachine
source?principal
target<OpsWorks-managed EC2 instances in ?stack>
permissionsopsworks:UpdateStack
conditionsservice_state trigger_exists
state logicACTIVE 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.'
move · open · esc close