gcp-orgpolicy-modify-drs-guardrail

Weaken iam.allowedPolicyMemberDomains to allow granting roles to external identities.

derived gcp emits CanModifyPolicy

match

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

{'principal': None} CanModifyPolicy {'orgpolicy': None}

where

node_type(?orgpolicy) == OrganizationPolicy ?orgpolicy.constraint == 'constraints/iam.allowedPolicyMemberDomains' ?orgpolicy is ENFORCED at/inherited-to ?scope (list constraint restricting allowed domains) ?principal has EFFECTIVE orgpolicy.policy.set at ?scope

emit

source typeIdentity
target type*
source?principal
target?orgpolicy
permissionsorgpolicy.policy.set
conditionsguardrail_enforced iam_permission
state logicACTIVE for the CanModifyPolicy when set is unconditional and the list constraint is enforced at ?scope. The unblocked cross-org grant edge is upgraded by hierarchy-chains; it additionally requires the principal to hold a setIamPolicy grant capability to actually add the external member (that capability is the identity-escalation.yaml edge, not this one).

Narrative

{principal.name} can weaken constraints/iam.allowedPolicyMemberDomains at {scope.name}, allowing external attacker-owned identities to be granted IAM roles in {scope.name} (cross-org grant).

Raw rule rules/derived/gcp/orgpolicy.yaml

id: gcp-orgpolicy-modify-drs-guardrail
emits: CanModifyPolicy
description: Weaken iam.allowedPolicyMemberDomains to allow granting roles to external identities.
match:
- - principal: null
  - CanModifyPolicy
  - orgpolicy: null
where:
- node_type(?orgpolicy) == OrganizationPolicy
- ?orgpolicy.constraint == 'constraints/iam.allowedPolicyMemberDomains'
- ?orgpolicy is ENFORCED at/inherited-to ?scope (list constraint restricting allowed domains)
- ?principal has EFFECTIVE orgpolicy.policy.set at ?scope
emit:
  source_type: Identity
  target_type: '*'
  source: ?principal
  target: ?orgpolicy
  permissions:
  - orgpolicy.policy.set
  gates:
  - 'external-member grant / CrossProjectTrust / CanFederateAs  # add an attacker-owned external principal
    via setIamPolicy'
  conditions:
  - guardrail_enforced
  - iam_permission
  state_logic: ACTIVE for the CanModifyPolicy when set is unconditional and the list constraint is enforced
    at ?scope. The unblocked cross-org grant edge is upgraded by hierarchy-chains; it additionally requires
    the principal to hold a setIamPolicy grant capability to actually add the external member (that capability
    is the identity-escalation.yaml edge, not this one).
  confidence: min(contributing_confidences)
  derived_from:
  - ?principal CanModifyPolicy ?orgpolicy
  - guardrail-removal-upgrades-blocked (hierarchy-chains.yaml)
  false_positive_note: "Domain Restricted Sharing only blocks ADDING out-of-domain members; it does not\
    \ itself grant anything. This rule is meaningful only when a cross-org/external-member grant edge\
    \ exists as BLOCKED by THIS policy AND the principal (or a reachable identity) can also perform the\
    \ setIamPolicy that would add the external member. Widening the allowed-domains list to include an\
    \ attacker domain is equivalent to removal \u2014 treat allowValues edits that add attacker-controllable\
    \ domains as weakening."
  narrative: '{principal.name} can weaken constraints/iam.allowedPolicyMemberDomains at {scope.name},
    allowing external attacker-owned identities to be granted IAM roles in {scope.name} (cross-org grant).'
move · open · esc close