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:

  1. Role or ClusterRole create/update/patch that grants high-risk permissions (wildcards, escalate / bind / impersonate, secret read, or privileged API resources such as pods/exec and serviceaccounts/token)
  2. 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_values and Esql.gcp_audit_resource_name_values for the Role/ClusterRole and workload objects touched.
  • Inspect Esql.user_agent_original_values and Esql.source_ip_values for 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

to-top