Kubernetes RBAC Wildcard Elevation on Existing Role

edit
IMPORTANT: This documentation is no longer updated. Refer to Elastic's version policy and the latest documentation.

Kubernetes RBAC Wildcard Elevation on Existing Role

edit

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.

Rule type: esql

Rule indices: None

Severity: high

Risk score: 73

Runs every: 5m

Searches indices from: now-9m (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References:

Tags:

  • Data Source: Kubernetes
  • Domain: Kubernetes
  • Use Case: Threat Detection
  • Tactic: Privilege Escalation
  • Resources: Investigation Guide

Version: 2

Rule authors:

  • Elastic

Rule license: Elastic License v2

Investigation guide

edit

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).

Rule query

edit
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

Framework: MITRE ATT&CKTM