aws-opsworks-update-user-profile-ssh-key

opsworks:UpdateUserProfile overwrites an OpsWorks user's SSH public key; OpsWorks propagates it to all stack instances at the next configure event, giving SSH access.

derived aws emits CanExecuteCommand

match

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

{'principal': None} HasPermission {'target_user': None}

where

node_type(?target_user) in [HumanIdentity, GenericIdentity] ?target_user has an OpsWorks UserProfile (AWS::OpsWorks::UserProfile) ?principal has effective opsworks:UpdateUserProfile (resource: * — no stack scope) ?target_user has SSH access (AllowSelfManagement or OpsWorks SSH permission) on at least one stack with ONLINE instances

emit

source typeIdentity
target typeVirtualMachine
source?principal
target<ONLINE OpsWorks instances the ?target_user has SSH access to>
permissionsopsworks:UpdateUserProfile
conditionstrigger_exists service_state
state logicCONDITIONAL(trigger_exists) — the SSH key is propagated only at the next configure lifecycle event (triggered by a deployment or instance restart). ACTIVE when a configure deployment is imminent or the attacker can also trigger one (opsworks:CreateDeployment). CONDITIONAL(service_state) if all instances are stopped. BLOCKED if opsworks:UpdateUserProfile is denied.

Narrative

{principal.name} can call opsworks:UpdateUserProfile to overwrite {target_user.name}'s SSH public key; OpsWorks propagates it to all instances in stacks where {target_user.name} has SSH access at the next configure event, enabling SSH command execution on those instances.

Raw rule rules/derived/aws/opsworks.yaml

id: aws-opsworks-update-user-profile-ssh-key
emits: CanExecuteCommand
description: opsworks:UpdateUserProfile overwrites an OpsWorks user's SSH public key; OpsWorks propagates
  it to all stack instances at the next configure event, giving SSH access.
match:
- - principal: null
  - HasPermission
  - target_user: null
where:
- node_type(?target_user) in [HumanIdentity, GenericIdentity]
- ?target_user has an OpsWorks UserProfile (AWS::OpsWorks::UserProfile)
- "?principal has effective opsworks:UpdateUserProfile (resource: * \u2014 no stack scope)"
- ?target_user has SSH access (AllowSelfManagement or OpsWorks SSH permission) on at least one stack with
  ONLINE instances
emit:
  source_type: Identity
  target_type: VirtualMachine
  source: ?principal
  target: <ONLINE OpsWorks instances the ?target_user has SSH access to>
  permissions:
  - opsworks:UpdateUserProfile
  conditions:
  - trigger_exists
  - service_state
  state_logic: "CONDITIONAL(trigger_exists) \u2014 the SSH key is propagated only at the next configure\
    \ lifecycle event (triggered by a deployment or instance restart). ACTIVE when a configure deployment\
    \ is imminent or the attacker can also trigger one (opsworks:CreateDeployment). CONDITIONAL(service_state)\
    \ if all instances are stopped. BLOCKED if opsworks:UpdateUserProfile is denied."
  confidence: 0.75
  derived_from:
  - ?principal HasPermission ?target_user (opsworks:UpdateUserProfile)
  - ?target_user OpsWorks UserProfile SSH key propagation to stack instances
  false_positive_note: 'Lower confidence (0.75) because two steps are required: (a) key overwrite and
    (b) a configure event must fire to propagate the key to instances. If the attacker cannot also trigger
    a deployment, the window is CONDITIONAL(trigger_exists). opsworks:UpdateUserProfile is account-level
    (no stack-level resource scope), so it applies to all OpsWorks users'' profiles in the account. Target
    the instances in stacks where the user has SSH permission (from opsworks:DescribePermissions). Only
    emit if the target user actually has SSH access to at least one stack.'
  narrative: '{principal.name} can call opsworks:UpdateUserProfile to overwrite {target_user.name}''s
    SSH public key; OpsWorks propagates it to all instances in stacks where {target_user.name} has SSH
    access at the next configure event, enabling SSH command execution on those instances.'
move · open · esc close