gcp-dm-executes-as
Every Deployment Manager deployment runs as the Google APIs service agent (PROJECT_NUMBER@cloudservices.gserviceaccount.com), which by default holds roles/editor at the project.
match (record)
{
"resource_type": "google.deploymentmanager.Deployment"
}
where
?sa = PROJECT_NUMBER@cloudservices.gserviceaccount.com (derived from deployment.projectNumber, not operation.user)
?sa.privilege_level is elevated (roles/editor) or admin (roles/owner) at project scope
emit
| source type | BuildWorker |
|---|---|
| target type | ServiceAccount |
| source | <Deployment node> |
| target | <cloudservices ServiceAccount> |
| conditions | service_state |
| state logic | ACTIVE when the deployment object exists and is not in a terminal-failure state; CONDITIONAL(service_state) if the deployment is in preview mode (actuation has not occurred) or is stopped/cancelled before resource creation. The service agent identity binding is structural — it cannot be changed per-deployment. |
Narrative
Deployment {deployment.name} executes as the Google APIs service agent {sa.name} ({sa.email}), which holds {sa.effective_roles} at the project. Code injected into the deployment config runs with those privileges.
Raw rule rules/derived/gcp/deploymentmanager.yaml
id: gcp-dm-executes-as
emits: ExecutesAs
description: Every Deployment Manager deployment runs as the Google APIs service agent (PROJECT_NUMBER@cloudservices.gserviceaccount.com),
which by default holds roles/editor at the project.
match_record:
resource_type: google.deploymentmanager.Deployment
where:
- ?sa = PROJECT_NUMBER@cloudservices.gserviceaccount.com (derived from deployment.projectNumber, not operation.user)
- ?sa.privilege_level is elevated (roles/editor) or admin (roles/owner) at project scope
emit:
target_type: ServiceAccount
source_type: BuildWorker
source: <Deployment node>
target: <cloudservices ServiceAccount>
permissions: []
conditions:
- service_state
state_logic: "ACTIVE when the deployment object exists and is not in a terminal-failure state; CONDITIONAL(service_state)\
\ if the deployment is in preview mode (actuation has not occurred) or is stopped/cancelled before\
\ resource creation. The service agent identity binding is structural \u2014 it cannot be changed\
\ per-deployment."
confidence: 1.0
derived_from: []
false_positive_note: "This is a structural fact, not an attack. The edge becomes attack-relevant only\
\ when combined with CanModifyCode (deployer can inject a malicious config). The service agent's roles\
\ must be resolved from the project IAM policy \u2014 do not assume roles/editor is still bound; org\
\ policy iam.automaticIamGrantsForDefaultServiceAccounts may have removed it, or the SA may have been\
\ restricted by an administrator."
narrative: Deployment {deployment.name} executes as the Google APIs service agent {sa.name} ({sa.email}),
which holds {sa.effective_roles} at the project. Code injected into the deployment config runs with
those privileges.