federate-then-enter-project

Federating into a ServiceAccount homed in a GCP project gives the federated principal a foothold in that project.

derived any cloud emits CanEnterProject

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] node_type(home_boundary(?internal)) == Project # GCP home_boundary(?internal) is a boundary the federated principal is not already in

emit

source typeIdentity
target typeProject
source?p
targethome_boundary(?internal) (Project)
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 project {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-project
emits: CanEnterProject
description: Federating into a ServiceAccount homed in a GCP project gives the federated principal a foothold
  in that project.
applies_to:
- '*'
match:
- - p: null
  - CanFederateAs
  - internal: null
where:
- node_type(?internal) in [Role, ServiceAccount, MachineIdentity]
- node_class(?p) in [Identity]
- 'node_type(home_boundary(?internal)) == Project   # GCP'
- home_boundary(?internal) is a boundary the federated principal is not already in
emit:
  source_type: Identity
  target_type: Project
  source: ?p
  target: home_boundary(?internal)  (Project)
  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) == Project
  false_positive_note: "The foothold is entry AS ?internal \u2014 WIF-into-a-ServiceAccount grants the\
    \ federated principal whatever the SA can do in the project, NOT the project's full privilege (boundary\
    \ control only if the SA is itself a project admin \u2014 see hierarchy-chains enter-boundary-rollups).\
    \ Do NOT emit for a federation whose target is homed in the principal's OWN project (no boundary crossed).\
    \ 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 project {boundary.name};
    the federation therefore lands the attacker inside {boundary.name}, operating as {internal.name}.'
move · open · esc close