Detection rules › Elastic
GKE Service Account Modified RBAC Objects
Detects write operations performed by GKE service accounts against RBAC resources (Roles, ClusterRoles, RoleBindings, ClusterRoleBindings). Service accounts typically do not manage RBAC directly; this activity may indicate token abuse or unauthorized privilege escalation.
Known false positives
- In-cluster controllers, operators, and CI jobs may legitimately reconcile RBAC manifests. Baseline known automation service accounts before tuning.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- Attach to cluster-admin Role (Falco)
- ClusterRole With Pod Exec Created (Falco)
- ClusterRole With Wildcard Created (Falco)
- ClusterRole With Write Privileges Created (Falco)
- Direct Interactive Kubernetes API Request by Unusual Utilities (Elastic)
- GKE Cluster-Admin Role Binding Created or Modified (Elastic)
- GKE Creation of a RoleBinding Referencing a ServiceAccount (Elastic)
- GKE Creation or Modification of Sensitive Role (Elastic)
Rule body
[metadata]
creation_date = "2026/07/10"
integration = ["gcp"]
maturity = "production"
updated_date = "2026/07/10"
[rule]
author = ["Elastic"]
description = """
Detects write operations performed by GKE service accounts against RBAC resources (Roles, ClusterRoles, RoleBindings,
ClusterRoleBindings). Service accounts typically do not manage RBAC directly; this activity may indicate token abuse or
unauthorized privilege escalation.
"""
false_positives = [
"""
In-cluster controllers, operators, and CI jobs may legitimately reconcile RBAC manifests. Baseline known automation
service accounts before tuning.
""",
]
from = "now-6m"
index = ["logs-gcp.audit-*"]
language = "kuery"
license = "Elastic License v2"
name = "GKE Service Account Modified RBAC Objects"
note = """## Triage and analysis
### Investigating GKE Service Account Modified RBAC Objects
This rule detects service accounts performing allowed write actions on RBAC resources. Stolen or over-privileged service
account tokens can silently alter authorization to gain or retain elevated access.
### Possible investigation steps
- Review `client.user.email`, `event.action`, and `gcp.audit.resource_name`.
- Trace the acting service account to its owning workload and inspect recent image changes or exec activity.
- Correlate with change tickets or GitOps commits for the same RBAC object.
### False positive analysis
- Platform operators and GitOps controllers running in-cluster commonly create or patch RBAC objects.
### Response and remediation
- Revert unauthorized RBAC changes, rotate the service account credentials, and tighten RBAC for the workload.
"""
setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
references = [
"https://kubernetes.io/docs/reference/access-authn-authz/rbac/",
"https://heilancoos.github.io/research/2025/12/16/kubernetes.html#overly-permissive-role-based-access-control",
]
risk_score = 47
rule_id = "c41e9854-3df3-465a-8234-4d625084ff86"
severity = "medium"
tags = [
"Domain: Cloud",
"Domain: Kubernetes",
"Data Source: GCP",
"Data Source: Google Cloud Platform",
"Use Case: Threat Detection",
"Tactic: Privilege Escalation",
"Tactic: Persistence",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:gcp.audit and service.name:"k8s.io" and event.outcome:success and
client.user.email:(system\:serviceaccount\:* and not (
"system:serviceaccount:kube-system:clusterrole-aggregation-controller" or
"system:serviceaccount:kube-system:generic-garbage-collector"
)) and event.action:(
"io.k8s.authorization.rbac.v1.clusterrolebindings.create" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.delete" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.patch" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.update" or
"io.k8s.authorization.rbac.v1.clusterroles.create" or
"io.k8s.authorization.rbac.v1.clusterroles.delete" or
"io.k8s.authorization.rbac.v1.clusterroles.patch" or
"io.k8s.authorization.rbac.v1.clusterroles.update" or
"io.k8s.authorization.rbac.v1.rolebindings.create" or
"io.k8s.authorization.rbac.v1.rolebindings.delete" or
"io.k8s.authorization.rbac.v1.rolebindings.patch" or
"io.k8s.authorization.rbac.v1.rolebindings.update" or
"io.k8s.authorization.rbac.v1.roles.create" or
"io.k8s.authorization.rbac.v1.roles.delete" or
"io.k8s.authorization.rbac.v1.roles.patch" or
"io.k8s.authorization.rbac.v1.roles.update"
)
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1098"
name = "Account Manipulation"
reference = "https://attack.mitre.org/techniques/T1098/"
[[rule.threat.technique.subtechnique]]
id = "T1098.006"
name = "Additional Container Cluster Roles"
reference = "https://attack.mitre.org/techniques/T1098/006/"
[rule.threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1098"
name = "Account Manipulation"
reference = "https://attack.mitre.org/techniques/T1098/"
[[rule.threat.technique.subtechnique]]
id = "T1098.006"
name = "Additional Container Cluster Roles"
reference = "https://attack.mitre.org/techniques/T1098/006/"
[rule.threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[rule.investigation_fields]
field_names = [
"@timestamp",
"client.user.email",
"source.ip",
"user_agent.original",
"event.action",
"event.outcome",
"gcp.audit.resource_name",
"gcp.audit.request.kind",
"data_stream.namespace",
]
Stages and Predicates
Stage 1: query
data_stream.dataset:gcp.audit and service.name:"k8s.io" and event.outcome:success and
client.user.email:(system\:serviceaccount\:* and not (
"system:serviceaccount:kube-system:clusterrole-aggregation-controller" or
"system:serviceaccount:kube-system:generic-garbage-collector"
)) and event.action:(
"io.k8s.authorization.rbac.v1.clusterrolebindings.create" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.delete" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.patch" or
"io.k8s.authorization.rbac.v1.clusterrolebindings.update" or
"io.k8s.authorization.rbac.v1.clusterroles.create" or
"io.k8s.authorization.rbac.v1.clusterroles.delete" or
"io.k8s.authorization.rbac.v1.clusterroles.patch" or
"io.k8s.authorization.rbac.v1.clusterroles.update" or
"io.k8s.authorization.rbac.v1.rolebindings.create" or
"io.k8s.authorization.rbac.v1.rolebindings.delete" or
"io.k8s.authorization.rbac.v1.rolebindings.patch" or
"io.k8s.authorization.rbac.v1.rolebindings.update" or
"io.k8s.authorization.rbac.v1.roles.create" or
"io.k8s.authorization.rbac.v1.roles.delete" or
"io.k8s.authorization.rbac.v1.roles.patch" or
"io.k8s.authorization.rbac.v1.roles.update"
)
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
client.user.email | in | system:serviceaccount:kube-system:clusterrole-aggregation-controller, system:serviceaccount:kube-system:generic-garbage-collector | excludes:client.user.email field:"client.user.email" value:"system:serviceaccount:kube-system:clusterrole-aggregation-controller" field:"client.user.email" value:"system:serviceaccount:kube-system:generic-garbage-collector" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
client.user.email | wildcard |
| field:"client.user.email" kind:wildcard value:"system:serviceaccount:*" |
data_stream.dataset | eq |
| field:"data_stream.dataset" kind:eq value:"gcp.audit" |
event.action | in |
| field:"EventType" kind:in |
event.outcome | eq |
| field:"event.outcome" kind:eq value:"success" |
service.name | eq |
| field:"ServiceName" kind:eq value:"k8s.io" |