gcp-deploy-cross-project-exec-sa
A Cloud Deploy target's execution SA from a different project establishes a cross-project trust enabling CanEnterProject on that SA's home project.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?deploy_worker) ==
BuildWorker
?pipeline_project = project_of(?deploy_worker)
?exec_sa_project = project_of(?exec_sa)
?exec_sa_project != ?pipeline_project
emit
| source type | Project |
|---|---|
| target type | Project |
| source | ?pipeline_project |
| target | ?exec_sa_project |
| permissions | iam.serviceAccounts.actAs (granted cross-project) |
| conditions | iam_permission resource_policy |
| state logic | ACTIVE when the execution SA is confirmed in a different project and the cross-project actAs grant is in place (required for Cloud Deploy to use it). hierarchy-chains enter-boundary-rollups and federation-chains federate-then-enter-project collapse this CrossProjectTrust + CanExecuteAs into CanEnterProject(?principal → exec_sa_project). |
Narrative
Cloud Deploy pipeline in project {pipeline_project.name} uses execution SA {exec_sa.name} from project {exec_sa_project.name} - a cross-project trust between the two projects. An attacker who executes as {exec_sa.name} via a rollout gains a foothold in {exec_sa_project.name}. hierarchy-chains enter-boundary-rollups collapses this CrossProjectTrust into CanEnterProject({principal} → {exec_sa_project.name}).
Raw rule rules/derived/gcp/clouddeploy.yaml
id: gcp-deploy-cross-project-exec-sa
emits: CrossProjectTrust
description: A Cloud Deploy target's execution SA from a different project establishes a cross-project
trust enabling CanEnterProject on that SA's home project.
applies_to:
- gcp
match:
- - deploy_worker: null
- ExecutesAs
- exec_sa: null
where:
- node_type(?deploy_worker) == BuildWorker
- ?pipeline_project = project_of(?deploy_worker)
- ?exec_sa_project = project_of(?exec_sa)
- ?exec_sa_project != ?pipeline_project
emit:
source_type: Project
target_type: Project
source: ?pipeline_project
target: ?exec_sa_project
permissions:
- iam.serviceAccounts.actAs (granted cross-project)
conditions:
- iam_permission
- resource_policy
state_logic: "ACTIVE when the execution SA is confirmed in a different project and the cross-project\
\ actAs grant is in place (required for Cloud Deploy to use it). hierarchy-chains enter-boundary-rollups\
\ and federation-chains federate-then-enter-project collapse this CrossProjectTrust + CanExecuteAs\
\ into CanEnterProject(?principal \u2192 exec_sa_project)."
confidence: 0.85
derived_from:
- ?deploy_worker ExecutesAs ?exec_sa (gcp-deploy-executes-as)
- cross-project SA membership
false_positive_note: "CrossProjectTrust is a structural fact, not an attack step by itself. The hierarchy-chains\
\ roll-up turns it into CanEnterProject only when combined with a CanExecuteAs path that reaches ?exec_sa.\
\ Confirm the SA is in a different project (?exec_sa_project != ?pipeline_project) before emitting.\
\ Both source and target must be Project nodes bound by the where-clause. The cross-project actAs\
\ org-policy constraint (iam.allowedPolicyMemberDomains) may restrict this \u2014 emit BLOCKED if\
\ the org policy denies cross-project SA usage and no override exists."
narrative: "Cloud Deploy pipeline in project {pipeline_project.name} uses execution SA {exec_sa.name}\
\ from project {exec_sa_project.name} \u2014 a cross-project trust between the two projects. An attacker\
\ who executes as {exec_sa.name} via a rollout gains a foothold in {exec_sa_project.name}. hierarchy-chains\
\ enter-boundary-rollups collapses this CrossProjectTrust into CanEnterProject({principal} \u2192\
\ {exec_sa_project.name})."