[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:
+17
-20
@@ -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]]
|
||||
|
||||
+95
@@ -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/"
|
||||
Reference in New Issue
Block a user