gcp-orgpolicy-modify-sa-key-upload-guardrail
Remove iam.disableServiceAccountKeyUpload to allow binding an attacker keypair to an SA.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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 |
| 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. |
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}.'