gcp-orgpolicy-modify-sa-key-upload-guardrail

Remove iam.disableServiceAccountKeyUpload to allow binding an attacker keypair to an SA.

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.disableServiceAccountKeyUpload' ?orgpolicy is ENFORCED at/inherited-to ?scope (boolean enforce==true) ?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 when set permission is unconditional and the constraint is enforced at ?scope; else CONDITIONAL(iam_permission)/BLOCKED as usual. Downstream upload-key edge upgrade deferred to hierarchy-chains.

Narrative

{principal.name} can remove constraints/iam.disableServiceAccountKeyUpload at {scope.name}, re-enabling upload of an attacker-controlled public key to service accounts in {scope.name}.

Raw rule rules/derived/gcp/orgpolicy.yaml

id: gcp-orgpolicy-modify-sa-key-upload-guardrail
emits: CanModifyPolicy
description: Remove iam.disableServiceAccountKeyUpload to allow binding an attacker keypair to an SA.
match:
- - principal: null
  - CanModifyPolicy
  - orgpolicy: null
where:
- node_type(?orgpolicy) == OrganizationPolicy
- ?orgpolicy.constraint == 'constraints/iam.disableServiceAccountKeyUpload'
- ?orgpolicy is ENFORCED at/inherited-to ?scope (boolean enforce==true)
- ?principal has EFFECTIVE orgpolicy.policy.set at ?scope
emit:
  source_type: Identity
  target_type: '*'
  source: ?principal
  target: ?orgpolicy
  permissions:
  - orgpolicy.policy.set
  gates:
  - 'CanCreateCredentialFor / CanModifyTrust(Identity -> ServiceAccount)  # upload attacker public key
    to SA'
  conditions:
  - guardrail_enforced
  - iam_permission
  state_logic: ACTIVE when set permission is unconditional and the constraint is enforced at ?scope; else
    CONDITIONAL(iam_permission)/BLOCKED as usual. Downstream upload-key edge upgrade deferred to hierarchy-chains.
  confidence: min(contributing_confidences)
  derived_from:
  - ?principal CanModifyPolicy ?orgpolicy
  - guardrail-removal-upgrades-blocked (hierarchy-chains.yaml)
  false_positive_note: "Uploading a public key to an SA also requires iam.serviceAccountKeys.create (upload\
    \ variant) on the SA itself \u2014 this rule only lifts the org-policy BLOCK; the caller still needs\
    \ the SA-scoped key permission for the unblocked edge to be ACTIVE. Keep the upgrade CONDITIONAL until\
    \ both hold."
  narrative: '{principal.name} can remove constraints/iam.disableServiceAccountKeyUpload at {scope.name},
    re-enabling upload of an attacker-controlled public key to service accounts in {scope.name}.'
move · open · esc close