federate-then-enter-project
Federating into a ServiceAccount homed in a GCP project gives the federated principal a foothold in that project.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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) |
| 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. |
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}.'