gcp-gke-create-nodepool-as-sa
container.nodePools.create + iam.serviceAccounts.actAs on a chosen SA => create a new node pool running as that SA; pods on those nodes read the node SA token via the metadata server (legacy metadata mode).
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has EFFECTIVE container.nodePools.create on the cluster
?sa is the target node SA (config.serviceAccount in the new node pool)
?principal has iam.serviceAccounts.actAs on ?sa (GKE requires actAs to bind a SA to a node pool)
the new node pool uses EXPOSE_ALL_SCOPES metadata mode OR WI is disabled on the cluster (so pods can reach the node SA metadata)
emit
| source type | Identity |
|---|---|
| target type | ServiceAccount |
| source | ?principal |
| target | ?sa |
| permissions | container.nodePools.create iam.serviceAccounts.actAs |
| conditions | iam_permission role_compatibility service_state |
| state logic | ACTIVE when both container.nodePools.create AND iam.serviceAccounts.actAs are confirmed and the node pool will use EXPOSE_ALL_SCOPES (or the cluster has WI disabled). POTENTIAL(role_compatibility) if the node pool SA permissibility is uncertain (the target SA may already be in use and GKE may reject re-binding). CONDITIONAL(service_state) until the node pool nodes are running and pods are scheduled. |
Narrative
{principal.name} can create a new node pool for cluster {cluster.name} bound to {sa.name} (container.nodePools.create + iam.serviceAccounts.actAs); pods scheduled on those nodes can read {sa.name}'s OAuth token from the GCE metadata server, executing with its cloud IAM permissions.
Raw rule rules/derived/gcp/gke.yaml
id: gcp-gke-create-nodepool-as-sa
emits: CanCreateWorkloadAs
description: container.nodePools.create + iam.serviceAccounts.actAs on a chosen SA => create a new node
pool running as that SA; pods on those nodes read the node SA token via the metadata server (legacy
metadata mode).
match:
- - principal: null
- CanPassIdentity
- sa: null
where:
- ?principal has EFFECTIVE container.nodePools.create on the cluster
- ?sa is the target node SA (config.serviceAccount in the new node pool)
- ?principal has iam.serviceAccounts.actAs on ?sa (GKE requires actAs to bind a SA to a node pool)
- the new node pool uses EXPOSE_ALL_SCOPES metadata mode OR WI is disabled on the cluster (so pods can
reach the node SA metadata)
emit:
source_type: Identity
target_type: ServiceAccount
source: ?principal
target: ?sa
permissions:
- container.nodePools.create
- iam.serviceAccounts.actAs
conditions:
- iam_permission
- role_compatibility
- service_state
state_logic: ACTIVE when both container.nodePools.create AND iam.serviceAccounts.actAs are confirmed
and the node pool will use EXPOSE_ALL_SCOPES (or the cluster has WI disabled). POTENTIAL(role_compatibility)
if the node pool SA permissibility is uncertain (the target SA may already be in use and GKE may reject
re-binding). CONDITIONAL(service_state) until the node pool nodes are running and pods are scheduled.
confidence: 0.85
derived_from:
- <gcp/identity-escalation.yaml gcp-sa-act-as CanPassIdentity edge>
- '<effective iam_permission: container.nodePools.create on cluster>'
false_positive_note: "container.nodePools.create requires iam.serviceAccounts.actAs on the SA to bind\
\ it to the node pool \u2014 without actAs GKE rejects the request. The node SA token is only accessible\
\ to pods if workloadMetadataConfig is NOT set to GKE_METADATA (downgrade to POTENTIAL if WI is enforced\
\ cluster-wide). Adding a node pool with GKE_METADATA still enabled means pods get scoped WI tokens,\
\ not the node SA \u2014 so the token-theft step does not apply. Only emit when legacy metadata access\
\ is confirmed (or will be configured on the new node pool). GKE Autopilot clusters do NOT allow custom\
\ node pools \u2014 BLOCKED for Autopilot."
narrative: '{principal.name} can create a new node pool for cluster {cluster.name} bound to {sa.name}
(container.nodePools.create + iam.serviceAccounts.actAs); pods scheduled on those nodes can read {sa.name}''s
OAuth token from the GCE metadata server, executing with its cloud IAM permissions.'