GKE Sensitive RBAC Change Followed by Workload Modification
Detects when the same GKE identity creates or modifies a Role or ClusterRole with high-risk permissions (wildcard access, RBAC escalation verbs, or access to secrets / privileged APIs) and also creates or patches a DaemonSet, Deployment, or CronJob within five minutes. This correlation is consistent with RBAC-based privilege escalation followed by payload deployment.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/07/17"
3integration = ["gcp"]
4maturity = "production"
5updated_date = "2026/09/18"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects when the same GKE identity creates or modifies a Role or ClusterRole with high-risk permissions
11(wildcard access, RBAC escalation verbs, or access to secrets / privileged APIs) and also creates or patches
12a DaemonSet, Deployment, or CronJob within five minutes. This correlation is consistent with RBAC-based
13privilege escalation followed by payload deployment.
14"""
15false_positives = [
16 """
17 GitOps or platform controllers that sync sensitive Roles and immediately reconcile DaemonSets, Deployments,
18 or CronJobs can match. Baseline approved automation after confirming the Role content is intentional.
19 """,
20 """
21 Coordinated maintenance that expands RBAC and rolls workloads in the same change window may alert; validate
22 against change tickets and the actor's expected client fingerprint.
23 """,
24]
25from = "now-11m"
26interval = "5m"
27language = "esql"
28license = "Elastic License v2"
29name = "GKE Sensitive RBAC Change Followed by Workload Modification"
30note = """## Triage and analysis
31
32### Investigating GKE Sensitive RBAC Change Followed by Workload Modification
33
34This ES|QL rule correlates two successful GKE audit behaviors from the same `client.user.email` within five
35minutes:
36
371. Role or ClusterRole create/update/patch that grants high-risk permissions (wildcards, `escalate` /
38 `bind` / `impersonate`, secret read, or privileged API resources such as `pods/exec` and
39 `serviceaccounts/token`)
402. DaemonSet, Deployment, or CronJob create or patch after the sensitive RBAC change
41
42`Esql.rbac_to_workload_minutes` is the gap from the latest sensitive RBAC event to the earliest workload
43modification in the lookback window.
44
45### Possible investigation steps
46
47- Review `Esql.event_action_values` and `Esql.gcp_audit_resource_name_values` for the Role/ClusterRole and
48 workload objects touched.
49- Inspect `Esql.user_agent_original_values` and `Esql.source_ip_values` for unexpected clients or networks.
50- Check for RoleBinding or ClusterRoleBinding activity around the same identity and time window.
51- Correlate with secret access, pod exec, or token creation from the same actor.
52
53### False positive analysis
54
55- GitOps pipelines that manage both RBAC manifests and workloads in one sync cycle.
56- Platform bootstrap that patches built-in roles and reconciles addon workloads.
57
58### Response and remediation
59
60- Roll back unauthorized Role/ClusterRole and workload changes, revoke the actor's credentials, and
61 tighten who can mutate RBAC and sensitive workloads.
62"""
63setup = """
64The GCP Fleet integration with GKE audit logs enabled is required. Request body capture on RBAC
65resources is required so Role and ClusterRole rule verbs and resources are present in
66`gcp.audit.request`.
67"""
68references = [
69 "https://heilancoos.github.io/research/2025/12/16/kubernetes.html#overly-permissive-role-based-access-control",
70 "https://kubernetes.io/docs/reference/access-authn-authz/rbac/",
71]
72risk_score = 47
73rule_id = "3ec2175d-8f34-4be9-b3be-c5821538760e"
74severity = "medium"
75tags = [
76 "Domain: Cloud",
77 "Domain: Kubernetes",
78 "Domain: Containers",
79 "Data Source: GCP",
80 "Data Source: Google Cloud Platform",
81 "Data Source: GCP Audit Logs",
82 "Platform: GCP",
83 "Platform: Kubernetes",
84 "Use Case: Threat Detection",
85 "Tactic: Privilege Escalation",
86 "Tactic: Persistence",
87 "Resources: Investigation Guide",
88 "Rule Type: ES|QL",
89 "Noise: Medium",
90 "Performance: Fast",
91]
92timestamp_override = "event.ingested"
93type = "esql"
94
95query = '''
96from logs-gcp.audit-* metadata _id, _index, _version
97| where data_stream.dataset == "gcp.audit"
98 and service.name == "k8s.io"
99 and event.outcome == "success"
100 and client.user.email is not null
101 and source.ip is not null
102 and not to_string(source.ip) in ("127.0.0.1", "::1")
103 and not client.user.email in (
104 "system:addon-manager",
105 "system:apiserver",
106 "system:kube-controller-manager",
107 "system:serviceaccount:flux-system:kustomize-controller",
108 "system:serviceaccount:flux-system:helm-controller",
109 "system:serviceaccount:flux-system:source-controller",
110 "system:serviceaccount:flux-system:flux-operator",
111 "system:serviceaccount:flux-operator:flux-operator"
112 )
113 and (
114 (
115 event.action in (
116 "io.k8s.authorization.rbac.v1.roles.create",
117 "io.k8s.authorization.rbac.v1.roles.update",
118 "io.k8s.authorization.rbac.v1.roles.patch",
119 "io.k8s.authorization.rbac.v1.clusterroles.create",
120 "io.k8s.authorization.rbac.v1.clusterroles.update",
121 "io.k8s.authorization.rbac.v1.clusterroles.patch"
122 )
123 and not (
124 client.user.email == "system:serviceaccount:kube-system:clusterrole-aggregation-controller"
125 and event.action == "io.k8s.authorization.rbac.v1.clusterroles.patch"
126 )
127 and (
128 KQL("""gcp.audit.request.rules.verbs:("*" or "escalate" or "bind" or "impersonate")""")
129 or KQL("""gcp.audit.request.rules.verbs:("*" or "create" or "patch" or "update") and gcp.audit.request.rules.resources:("*" or "clusterroles" or "clusterrolebindings" or "roles" or "rolebindings" or "pods/exec" or "serviceaccounts/token" or "nodes/proxy" or "daemonsets")""")
130 or KQL("""gcp.audit.request.rules.verbs:("*" or "get" or "list") and gcp.audit.request.rules.resources:("*" or "secrets")""")
131 )
132 )
133 or event.action in (
134 "io.k8s.apps.v1.daemonsets.create",
135 "io.k8s.apps.v1.daemonsets.patch",
136 "io.k8s.apps.v1.deployments.create",
137 "io.k8s.apps.v1.deployments.patch",
138 "io.k8s.batch.v1.cronjobs.create",
139 "io.k8s.batch.v1.cronjobs.patch"
140 )
141 )
142| eval Esql.is_sensitive_rbac = case(event.action like "io.k8s.authorization.rbac.*", 1, 0),
143 Esql.is_workload_modification = case(event.action like "io.k8s.apps.*" or event.action like "io.k8s.batch.*", 1, 0),
144 Esql.sensitive_rbac_timestamp = case(event.action like "io.k8s.authorization.rbac.*", @timestamp, null),
145 Esql.workload_modification_timestamp = case(event.action like "io.k8s.apps.*" or event.action like "io.k8s.batch.*", @timestamp, null)
146| stats
147 Esql.sensitive_rbac_count = sum(Esql.is_sensitive_rbac),
148 Esql.workload_modification_count = sum(Esql.is_workload_modification),
149 Esql.latest_sensitive_rbac_timestamp = max(Esql.sensitive_rbac_timestamp),
150 Esql.earliest_workload_modification_timestamp = min(Esql.workload_modification_timestamp),
151 Esql.event_action_values = values(event.action),
152 Esql.gcp_audit_resource_name_values = values(gcp.audit.resource_name),
153 Esql.user_agent_original_values = values(user_agent.original),
154 Esql.source_ip_values = values(source.ip)
155 by client.user.email
156| where Esql.sensitive_rbac_count > 0
157 and Esql.workload_modification_count > 0
158 and Esql.latest_sensitive_rbac_timestamp <= Esql.earliest_workload_modification_timestamp
159| eval Esql.rbac_to_workload_minutes = date_diff(
160 "minute",
161 Esql.latest_sensitive_rbac_timestamp,
162 Esql.earliest_workload_modification_timestamp
163 )
164| where Esql.rbac_to_workload_minutes <= 5
165| keep
166 client.user.email,
167 Esql.*
168'''
169
170[[rule.threat]]
171framework = "MITRE ATT&CK"
172
173[[rule.threat.technique]]
174id = "T1098"
175name = "Account Manipulation"
176reference = "https://attack.mitre.org/techniques/T1098/"
177
178[[rule.threat.technique.subtechnique]]
179id = "T1098.006"
180name = "Additional Container Cluster Roles"
181reference = "https://attack.mitre.org/techniques/T1098/006/"
182
183[rule.threat.tactic]
184id = "TA0004"
185name = "Privilege Escalation"
186reference = "https://attack.mitre.org/tactics/TA0004/"
187
188[[rule.threat]]
189framework = "MITRE ATT&CK"
190
191[[rule.threat.technique]]
192id = "T1098"
193name = "Account Manipulation"
194reference = "https://attack.mitre.org/techniques/T1098/"
195
196[[rule.threat.technique.subtechnique]]
197id = "T1098.006"
198name = "Additional Container Cluster Roles"
199reference = "https://attack.mitre.org/techniques/T1098/006/"
200
201[rule.threat.tactic]
202id = "TA0003"
203name = "Persistence"
204reference = "https://attack.mitre.org/tactics/TA0003/"
Triage and analysis
Investigating GKE Sensitive RBAC Change Followed by Workload Modification
This ES|QL rule correlates two successful GKE audit behaviors from the same client.user.email within five
minutes:
- Role or ClusterRole create/update/patch that grants high-risk permissions (wildcards,
escalate/bind/impersonate, secret read, or privileged API resources such aspods/execandserviceaccounts/token) - DaemonSet, Deployment, or CronJob create or patch after the sensitive RBAC change
Esql.rbac_to_workload_minutes is the gap from the latest sensitive RBAC event to the earliest workload
modification in the lookback window.
Possible investigation steps
- Review
Esql.event_action_valuesandEsql.gcp_audit_resource_name_valuesfor the Role/ClusterRole and workload objects touched. - Inspect
Esql.user_agent_original_valuesandEsql.source_ip_valuesfor unexpected clients or networks. - Check for RoleBinding or ClusterRoleBinding activity around the same identity and time window.
- Correlate with secret access, pod exec, or token creation from the same actor.
False positive analysis
- GitOps pipelines that manage both RBAC manifests and workloads in one sync cycle.
- Platform bootstrap that patches built-in roles and reconciles addon workloads.
Response and remediation
- Roll back unauthorized Role/ClusterRole and workload changes, revoke the actor's credentials, and tighten who can mutate RBAC and sensitive workloads.
References
Related rules
- GKE Certificate Signing Request Self-Approved
- GKE Certificate Signing Request API Client Signer Requested
- GKE Certificate Signing Request for Privileged Identity
- GKE Client Certificate Signing Request Created or Approved
- GKE Cluster-Admin Role Binding Created or Modified