aws-account-leave-org-escapes-scp
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_class(?account) == AdministrativeBoundary and node_type(?account) ==
Account
node_type(?scp) == ServiceControlPolicy # an SCP is actually attached to ?account (or its OU)
?principal has EFFECTIVE organizations:LeaveOrganization (member-side) OR organizations:RemoveAccountFromOrganization (management-side) for ?account
no SCP denies the leave/remove action itself at ?account scope
emit
| source type | Identity |
|---|---|
| target type | * |
| source | <principal> |
| target | <scope-binding of ?scp on ?account> |
| permissions | organizations:LeaveOrganization organizations:RemoveAccountFromOrganization |
| conditions | scp_or_org_policy service_state |
| state logic | ACTIVE when the leave/remove action is effectively held and NOT itself SCP-denied and the account is standalone-ready. CONDITIONAL(service_state) when RemoveAccountFromOrganization would fail because the member is not standalone-ready (billing/contact info incomplete). BLOCKED(scp_or_org_policy) when an SCP denies organizations:LeaveOrganization (standard landing-zone hardening) -- and note the circularity: you cannot leave to escape an SCP that denies leaving, so this edge cannot self-upgrade the very SCP blocking it. |
Narrative
{principal.name} can pull account {account.name} out of the organization (organizations:LeaveOrganization / RemoveAccountFromOrganization), detaching it from SCP {scp.name} and every guardrail that SCP imposes.
Raw rule rules/explicit/aws-account.yaml
id: aws-account-leave-org-escapes-scp
emits: CanModifyConfiguration
applies_to:
- aws
match:
- - principal: null
- HasPermission
- account: null
- - account: null
- HasPolicy
- scp: null
where:
- node_class(?account) == AdministrativeBoundary and node_type(?account) == Account
- 'node_type(?scp) == ServiceControlPolicy # an SCP is actually attached to ?account (or its OU)'
- ?principal has EFFECTIVE organizations:LeaveOrganization (member-side) OR organizations:RemoveAccountFromOrganization
(management-side) for ?account
- no SCP denies the leave/remove action itself at ?account scope
emit:
source_type: Identity
target_type: '*'
source: <principal>
target: <scope-binding of ?scp on ?account>
api_source: iam:SimulatePrincipalPolicy | policy evaluation
permissions:
- organizations:LeaveOrganization
- organizations:RemoveAccountFromOrganization
conditions:
- scp_or_org_policy
- service_state
state_logic: 'ACTIVE when the leave/remove action is effectively held and NOT itself SCP-denied and
the account is standalone-ready. CONDITIONAL(service_state) when RemoveAccountFromOrganization would
fail because the member is not standalone-ready (billing/contact info incomplete). BLOCKED(scp_or_org_policy)
when an SCP denies organizations:LeaveOrganization (standard landing-zone hardening) -- and note the
circularity: you cannot leave to escape an SCP that denies leaving, so this edge cannot self-upgrade
the very SCP blocking it.'
false_positive_note: Fire ONLY when an SCP is genuinely attached to ?account (else there is no guardrail
to escape and this is mere availability impact -- model as CanDelete, not a path). LeaveOrganization
is member-side and very commonly SCP-denied in hardened orgs -> BLOCKED. RemoveAccountFromOrganization
is management-side and requires the member to be standalone-ready (complete billing/contact) or the
API fails -> CONDITIONAL(service_state). Do not emit for the management account itself (it cannot
leave its own org). The BLOCKED->ACTIVE upgrade of the suppressed edges is owned by hierarchy-chains
rule 3, NOT here. The complementary POLICY-EDIT branch (organizations:UpdatePolicy/DetachPolicy/DeletePolicy/DisablePolicyType,
organizations:MoveAccount to an OU without the SCP) is emitted by the organizations adapter as CanModifyPolicy
over ?scp -- CITED, not here.
narrative: '{principal.name} can pull account {account.name} out of the organization (organizations:LeaveOrganization
/ RemoveAccountFromOrganization), detaching it from SCP {scp.name} and every guardrail that SCP imposes.'