federate-then-enter-account

Federating into a Role homed in an AWS account gives the federated principal a foothold in that account.

derived any cloud emits CanEnterAccount

match

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

{'p': None} CanFederateAs {'internal': None}

where

node_type(?internal) in [Role, ServiceAccount, MachineIdentity] node_class(?p) in [Identity] # FederatedIdentity / WorkloadIdentity are Identity subtypes node_type(home_boundary(?internal)) == Account # AWS home_boundary(?internal) is a boundary the federated principal is not already in

emit

source typeIdentity
target typeAccount
source?p
targethome_boundary(?internal) (Account)
conditionstrust_condition
state logicinherit from the CanFederateAs input: ACTIVE only when the federation is ACTIVE (broad/unpinned trust the attacker satisfies); CONDITIONAL(trust_condition) when the federation is CONDITIONAL (pinned trust); BLOCKED if the federation is BLOCKED. The foothold is exactly as strong as the takeover that produces it.

Narrative

{p.name} can federate in as {internal.name}, which is homed in account {boundary.name}; the federation therefore lands the attacker inside {boundary.name}, operating as {internal.name}.

Raw rule rules/derived/federation-chains.yaml

id: federate-then-enter-account
emits: CanEnterAccount
description: Federating into a Role homed in an AWS account gives the federated principal a foothold in
  that account.
applies_to:
- '*'
match:
- - p: null
  - CanFederateAs
  - internal: null
where:
- node_type(?internal) in [Role, ServiceAccount, MachineIdentity]
- 'node_class(?p) in [Identity]  # FederatedIdentity / WorkloadIdentity are Identity subtypes'
- 'node_type(home_boundary(?internal)) == Account   # AWS'
- home_boundary(?internal) is a boundary the federated principal is not already in
emit:
  source_type: Identity
  target_type: Account
  source: ?p
  target: home_boundary(?internal)  (Account)
  permissions: []
  conditions:
  - trust_condition
  state_logic: 'inherit from the CanFederateAs input: ACTIVE only when the federation is ACTIVE (broad/unpinned
    trust the attacker satisfies); CONDITIONAL(trust_condition) when the federation is CONDITIONAL (pinned
    trust); BLOCKED if the federation is BLOCKED. The foothold is exactly as strong as the takeover that
    produces it.'
  confidence: min(contributing_confidences)
  derived_from:
  - ?p CanFederateAs ?internal
  - home_boundary(?internal) == Account
  false_positive_note: "The foothold is entry AS ?internal \u2014 it grants the federated principal whatever\
    \ ?internal itself can do inside the account, NOT the account's full privilege (rule 1's trust breadth\
    \ decides reachability; boundary control comes only if ?internal is itself an admin there \u2014 see\
    \ hierarchy-chains enter-boundary-rollups for the Controls upgrade condition). Do NOT emit for a federation\
    \ whose target is homed in the principal's OWN account (no boundary crossed). AWS cross-account role\
    \ ASSUME (not federation) is already handled by can-control's enter-account-via-assume \u2014 do not\
    \ double-emit CanEnterAccount for that case; this rule covers the CanFederateAs (web-identity / RolesAnywhere)\
    \ path. Respect the trust_condition gate \u2014 never upgrade a CONDITIONAL federation to an ACTIVE\
    \ foothold."
  narrative: '{p.name} can federate in as {internal.name}, which is homed in account {boundary.name};
    the federation therefore lands the attacker inside {boundary.name}, operating as {internal.name}.'
move · open · esc close