[New/Tuning] K8 RBAC Privs (#5987)

* [New/Tuning] K8 RBAC Privs

- new rule with high severity for wildcards for both verb/resource
- added responseObject to an existing rule as on my testing it did not trigger on requestObject (unknown type of on EKS logs), also added few sensitive resources and adjusted logic to ignore list/get on things like roles/clusterroles etc.

* ++

* Rename persistence_kubernetes_role_patch_wildcard_verbs_resources_response.toml to  privilege_escalation_role_patch_wildcard_verbs_resources_response.toml

* Update and rename  privilege_escalation_role_patch_wildcard_verbs_resources_response.toml to privilege_escalation_role_patch_wildcard_verbs_resources_response.toml

* Update privilege_escalation_role_patch_wildcard_verbs_resources_response.toml

* Update privilege_escalation_role_patch_wildcard_verbs_resources_response.toml

* Update persistence_sensitive_role_creation_or_modification.toml

* Update persistence_sensitive_role_creation_or_modification.toml

* Update privilege_escalation_role_patch_wildcard_verbs_resources_response.toml
This commit is contained in:
Samirbous
2026-05-02 15:08:00 +01:00
committed by GitHub
parent 838e926058
commit 2e223459c4
2 changed files with 112 additions and 20 deletions
@@ -2,7 +2,7 @@
creation_date = "2026/02/04"
integration = ["kubernetes"]
maturity = "production"
updated_date = "2026/03/03"
updated_date = "2026/04/27"
[rule]
author = ["Elastic"]
@@ -68,25 +68,22 @@ FROM logs-kubernetes.audit_logs-* metadata _id, _index, _version
kubernetes.audit.verb in ("create", "update", "patch") and
`kubernetes.audit.annotations.authorization_k8s_io/decision` == "allow" and
kubernetes.audit.level == "RequestResponse" and kubernetes.audit.stage == "ResponseComplete" and
KQL("""kubernetes.audit.requestObject.rules.verbs:("*" or "escalate" or "bind" or "impersonate") or kubernetes.audit.requestObject.rules.resources:("clusterroles" or "clusterrolebindings" or "roles" or "rolebindings")""")
| KEEP
@timestamp,
data_stream.namespace,
`kubernetes.audit.annotations.authorization_k8s_io/decision`,
kubernetes.audit.level,
kubernetes.audit.objectRef.name,
kubernetes.audit.objectRef.resource,
kubernetes.audit.requestURI,
kubernetes.audit.responseStatus.code,
kubernetes.audit.sourceIPs,
kubernetes.audit.stage,
kubernetes.audit.user.groups,
kubernetes.audit.user.username,
user_agent.original,
kubernetes.audit.verb,
_id,
_index,
_version
not kubernetes.audit.sourceIPs in ("::1", "127.0.0.1") and
not (user.name like "eks:*" and kubernetes.audit.objectRef.name like "eks:*") and
not (user.name == "aksService" and event.action == "create" and kubernetes.audit.objectRef.name like "aks:*") and
not (user.name == "system:serviceaccount:kube-system:clusterrole-aggregation-controller" and kubernetes.audit.objectRef.name in ("admin", "edit") and event.action == "patch") and
(
// using requestObject
KQL(""" kubernetes.audit.requestObject.rules.verbs:("*" or "escalate" or "bind" or "impersonate") """) or
KQL(""" kubernetes.audit.requestObject.rules.verbs: ("*" or "create" or "patch" or "update") and kubernetes.audit.requestObject.rules.resources:("*" or "clusterroles" or "clusterrolebindings" or "roles" or "rolebindings" or "pods/exec" or "serviceaccounts/token" or "nodes/proxy" or "daemonsets") """) or
KQL(""" kubernetes.audit.requestObject.rules.verbs: ("*" or "get" or "list") and kubernetes.audit.requestObject.rules.resources:("*" or "secrets") """) or
// using responseObject
KQL(""" kubernetes.audit.responseObject.rules.verbs:("*" or "escalate" or "bind" or "impersonate") """) or
KQL(""" kubernetes.audit.responseObject.rules.verbs: ("*" or "create" or "patch" or "update") and kubernetes.audit.responseObject.rules.resources:("*" or "clusterroles" or "clusterrolebindings" or "roles" or "rolebindings" or "pods/exec" or "serviceaccounts/token" or "nodes/proxy" or "daemonsets") """) or
KQL(""" kubernetes.audit.responseObject.rules.verbs: ("*" or "get" or "list") and kubernetes.audit.responseObject.rules.resources:("*" or "secrets") """)
)
| keep user.name, user_agent.original, event.action, source.ip, kubernetes.audit.verb, kubernetes.audit.objectRef.resource, kubernetes.audit.objectRef.name, kubernetes.audit.requestURI, kubernetes.audit.user.username, kubernetes.audit.user.groups, `kubernetes.audit.annotations.authorization_k8s_io/decision`, event.original, _id, _version, _index, data_stream.namespace
'''
[[rule.threat]]
@@ -0,0 +1,95 @@
[metadata]
creation_date = "2026/04/27"
integration = ["kubernetes"]
maturity = "production"
updated_date = "2026/04/27"
[rule]
author = ["Elastic"]
description = """
Flags an existing Role or ClusterRole being changed (patch or update) so the effective rules become cluster-admin-like:
wildcard on every API resource and wildcard on every verb. That is usually a deliberate privilege expansion, not a typo.
RequestResponse audit and the response body are required so the detection reads the merged role after apply; loopback
source IPs are ignored.
"""
false_positives = [
"""
Platform installers, GitOps controllers, and emergency break-glass roles sometimes ship or widen wildcard
ClusterRoles; correlate with change records and narrow by user or service account when baselined.
""",
]
from = "now-9m"
interval = "5m"
language = "esql"
license = "Elastic License v2"
name = "Kubernetes RBAC Wildcard Elevation on Existing Role"
note = """## Triage and analysis
### Investigating Kubernetes RBAC Wildcard Elevation on Existing Role
Someone patched or updated a Role or ClusterRole so the stored rules grant star verbs and star resources—near
cluster-admin breadth on that scope. Confirm the actor (user, group, impersonation), client, and non-loopback source
IP; then see who can bind that role.
### Possible investigation steps
- Diff the role YAML before and after; list RoleBindings and ClusterRoleBindings that reference it and which subjects
gained the widened access.
- In the same window, check secret reads, exec, and further RBAC changes from the same identity.
### False positive analysis
- Approved GitOps or vendor upgrades sometimes widen a known ClusterRole; allowlist stable automation when documented.
### Response and remediation
- Revert the role, drop unexpected bindings, rotate credentials for the actor, and block future wildcard RBAC outside
governed pipelines (policy-as-code, PR-only RBAC).
"""
references = [
"https://attack.mitre.org/techniques/T1098/006/",
"https://kubernetes.io/docs/reference/access-authn-authz/rbac/",
]
risk_score = 73
rule_id = "c8f4a2e1-9b3d-4c7e-8f2a-1d0e5b6c7a89"
severity = "high"
tags = [
"Data Source: Kubernetes",
"Domain: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Privilege Escalation",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
from logs-kubernetes.audit_logs-* metadata _id, _index, _version
| where
kubernetes.audit.objectRef.resource in ("roles", "clusterroles") and
kubernetes.audit.verb in ("update", "patch") and
`kubernetes.audit.annotations.authorization_k8s_io/decision` == "allow" and
kubernetes.audit.level == "RequestResponse" and
kubernetes.audit.stage == "ResponseComplete" and
kubernetes.audit.sourceIPs is not null and
not kubernetes.audit.sourceIPs in ("::1", "127.0.0.1") and
KQL(""" kubernetes.audit.responseObject.rules.verbs:"*" and kubernetes.audit.responseObject.rules.resources:"*" """)
| keep user.name, user_agent.original, event.action, source.ip, kubernetes.audit.verb, kubernetes.audit.objectRef.resource, kubernetes.audit.objectRef.name, kubernetes.audit.requestURI, kubernetes.audit.user.username, kubernetes.audit.user.groups, `kubernetes.audit.annotations.authorization_k8s_io/decision`, event.original, _id, _version, _index, data_stream.namespace
'''
[[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/"