Kubernetes Role With Wildcard Permissions Created


Description

This detection monitors for Roles or ClusterRoles being created with wildcard (*) permissions in resources or verbs. Wildcard permissions grant overly broad access, such as all operations on all resources, which violates the principle of least privilege. Attackers who gain RBAC modification permissions often create wildcard roles to maximize their access across the cluster without knowing specific resource names or API operations.

Query · python

from panther_kubernetes_helpers import is_failed_request, is_system_principal, k8s_alert_context


def rule(event):
    verb = event.udm("verb")
    resource = event.udm("resource")
    username = event.udm("username")
    response_status = event.udm("responseStatus")

    # Only check Role/ClusterRole creation events
    if verb != "create" or resource not in {"roles", "clusterroles"}:
        return False

    # Skip failed requests
    if is_failed_request(response_status):
        return False

    # Exclude system principals to reduce false positives from legitimate operators
    if is_system_principal(username):
        return False

    # Check if role grants wildcard permissions
    request_object = event.udm("requestObject") or {}
    rules = request_object.get("rules") or []

    for rule_entry in rules:
        resources = rule_entry.get("resources") or []
        verbs = rule_entry.get("verbs") or []

        # Check for wildcard in resources or verbs
        if "*" in resources or "*" in verbs:
            return True

    return False


def title(event):
    username = event.udm("username") or "<UNKNOWN_USER>"
    resource = event.udm("resource") or "<UNKNOWN_RESOURCE>"
    name = event.udm("name") or "<UNKNOWN_ROLE>"
    namespace = event.udm("namespace") or "<CLUSTER_SCOPED>"

    role_type = "ClusterRole" if resource == "clusterroles" else "Role"

    if namespace != "<CLUSTER_SCOPED>":
        return f"[{username}] created {role_type} [{namespace}/{name}] with wildcard permissions"

    return f"[{username}] created {role_type} [{name}] with wildcard permissions "


def dedup(event):
    username = event.udm("username") or "<UNKNOWN_USER>"
    resource = event.udm("resource") or "<UNKNOWN_RESOURCE>"
    name = event.udm("name") or "<UNKNOWN_ROLE>"
    return f"k8s_role_wildcard_{username}_{resource}_{name}"


def severity(event):
    """ClusterRoles with wildcards are more dangerous than namespaced Roles."""
    resource = event.udm("resource") or ""

    # Critical for ClusterRole (cluster-wide wildcard permissions)
    if resource == "clusterroles":
        return "CRITICAL"

    # High for namespaced Role (namespace-scoped wildcard permissions)
    return "HIGH"


def alert_context(event):
    request_object = event.udm("requestObject") or {}
    rules = request_object.get("rules") or []

    # Extract only the rules that contain wildcards
    wildcard_rules = []
    for rule_entry in rules:
        resources = rule_entry.get("resources") or []
        verbs = rule_entry.get("verbs") or []
        if "*" in resources or "*" in verbs:
            wildcard_rules.append(rule_entry)

    return k8s_alert_context(
        event,
        extra_fields={
            "role_name": event.udm("name"),
            "role_type": event.udm("resource"),
            "wildcard_rules": wildcard_rules,
        },
    )

Analyst notes

  1. Review the role rules to identify the scope of wildcard permissions and determine if this role creation is expected
  2. Identify all API operations by the creating user in the 2 hours before and after the alert and search for RoleBindings or ClusterRoleBindings that reference this role
  3. If unauthorized, immediately delete the role and any bindings, then audit all API activity in the cluster in the past 24 hours to assess impact
Raw source Kubernetes Role With Wildcard Permissions Created · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
RuleID: "Kubernetes.Role.Wildcard"
DisplayName: "Kubernetes Role With Wildcard Permissions Created"
Enabled: true
Status: Experimental
Filename: k8s_role_wildcard.py
LogTypes:
  - Amazon.EKS.Audit
  - Azure.MonitorActivity
  - GCP.AuditLog
Tags:
  - Kubernetes
  - Privilege Escalation
  - Excessive Permissions
  - RBAC
  - Unified Detection
Severity: High
Description: >
  This detection monitors for Roles or ClusterRoles being created with wildcard (*) permissions in resources
  or verbs. Wildcard permissions grant overly broad access, such as all operations on all resources, which
  violates the principle of least privilege. Attackers who gain RBAC modification permissions often create
  wildcard roles to maximize their access across the cluster without knowing specific resource names or API operations.
Runbook: |
  1. Review the role rules to identify the scope of wildcard permissions and determine if this role creation is expected
  2. Identify all API operations by the creating user in the 2 hours before and after the alert and search for RoleBindings or ClusterRoleBindings that reference this role
  3. If unauthorized, immediately delete the role and any bindings, then audit all API activity in the cluster in the past 24 hours to assess impact
Reports:
  MITRE ATT&CK:
    - TA0004:T1078.004 # Privilege Escalation: Valid Accounts - Cloud Accounts
    - TA0005:T1078.004 # Defense Evasion: Valid Accounts - Cloud Accounts
Reference: >
  - https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping
  - https://hub.datree.io/built-in-rules/prevent-wildcards-role-clusterrole
DedupPeriodMinutes: 60
SummaryAttributes:
  - username
  - resource
  - name
  - p_source_label
Tests:
  - Name: EKS ClusterRole with wildcard resources and verbs
    ExpectedResult: true
    Log:
      {
        "kind": "Event",
        "apiVersion": "audit.k8s.io/v1",
        "verb": "create",
        "user": {"username": "attacker@example.com"},
        "sourceIPs": ["203.0.113.42"],
        "userAgent": "kubectl/v1.28.0",
        "objectRef": {
          "resource": "clusterroles",
          "name": "super-admin",
          "apiGroup": "rbac.authorization.k8s.io",
          "apiVersion": "v1"
        },
        "responseStatus": {"code": 201},
        "requestObject": {
          "kind": "ClusterRole",
          "metadata": {"name": "super-admin"},
          "rules": [
            {
              "apiGroups": ["*"],
              "resources": ["*"],
              "verbs": ["*"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit",
        "p_source_label": "eks-cluster"
      }
  - Name: AKS Role with wildcard verbs only
    ExpectedResult: true
    Log:
      {
        "p_log_type": "Azure.MonitorActivity",
        "category": "kube-audit",
        "operationName": "Microsoft.ContainerService/managedClusters/diagnosticLogs/Read",
        "properties": {
          "log": "{\"kind\":\"Event\",\"apiVersion\":\"audit.k8s.io/v1\",\"verb\":\"create\",\"user\":{\"username\":\"malicious-user@example.com\"},\"sourceIPs\":[\"1.2.3.4\"],\"objectRef\":{\"resource\":\"roles\",\"namespace\":\"production\",\"name\":\"pod-admin\",\"apiGroup\":\"rbac.authorization.k8s.io\"},\"responseStatus\":{\"code\":201},\"requestObject\":{\"kind\":\"Role\",\"metadata\":{\"name\":\"pod-admin\",\"namespace\":\"production\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"pods\"],\"verbs\":[\"*\"]}]}}"
        },
        "p_source_label": "aks-cluster"
      }
  - Name: GKE ClusterRole with wildcard resources only
    ExpectedResult: true
    Log:
      {
        "protoPayload": {
          "authenticationInfo": {"principalEmail": "user@company.com"},
          "authorizationInfo": [{
            "granted": true,
            "permission": "io.k8s.rbac.v1.clusterroles.create",
            "resource": "rbac.authorization.k8s.io/v1/clusterroles/all-reader"
          }],
          "methodName": "io.k8s.rbac.v1.clusterroles.create",
          "requestMetadata": {"callerIP": "8.8.8.8"},
          "resourceName": "rbac.authorization.k8s.io/v1/clusterroles/all-reader",
          "serviceName": "k8s.io",
          "request": {
            "kind": "ClusterRole",
            "metadata": {"name": "all-reader"},
            "rules": [
              {
                "apiGroups": [""],
                "resources": ["*"],
                "verbs": ["get", "list", "watch"]
              }
            ]
          }
        },
        "resource": {
          "type": "k8s_cluster",
          "labels": {"project_id": "test-project"}
        },
        "p_log_type": "GCP.AuditLog",
        "p_source_label": "gke-cluster"
      }
  - Name: EKS ClusterRole with multiple rules, one with wildcard
    ExpectedResult: true
    Log:
      {
        "kind": "Event",
        "verb": "create",
        "user": {"username": "suspicious-user@example.com"},
        "objectRef": {
          "resource": "clusterroles",
          "name": "mixed-permissions",
          "apiGroup": "rbac.authorization.k8s.io"
        },
        "responseStatus": {"code": 201},
        "requestObject": {
          "kind": "ClusterRole",
          "rules": [
            {
              "apiGroups": [""],
              "resources": ["pods"],
              "verbs": ["get", "list"]
            },
            {
              "apiGroups": ["*"],
              "resources": ["secrets"],
              "verbs": ["*"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit",
        "p_source_label": "eks-cluster"
      }
  - Name: Role with specific resources and verbs (no wildcard)
    ExpectedResult: false
    Log:
      {
        "kind": "Event",
        "verb": "create",
        "user": {"username": "admin@example.com"},
        "objectRef": {
          "resource": "roles",
          "namespace": "default",
          "name": "pod-reader",
          "apiGroup": "rbac.authorization.k8s.io"
        },
        "responseStatus": {"code": 201},
        "requestObject": {
          "kind": "Role",
          "rules": [
            {
              "apiGroups": [""],
              "resources": ["pods", "pods/log"],
              "verbs": ["get", "list"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit"
      }
  - Name: ClusterRole with wildcard apiGroups only (not resources or verbs)
    ExpectedResult: false
    Log:
      {
        "kind": "Event",
        "verb": "create",
        "user": {"username": "admin@example.com"},
        "objectRef": {
          "resource": "clusterroles",
          "name": "api-reader",
          "apiGroup": "rbac.authorization.k8s.io"
        },
        "responseStatus": {"code": 201},
        "requestObject": {
          "kind": "ClusterRole",
          "rules": [
            {
              "apiGroups": ["*"],
              "resources": ["deployments"],
              "verbs": ["get", "list"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit"
      }
  - Name: System principal creating role (excluded)
    ExpectedResult: false
    Log:
      {
        "kind": "Event",
        "verb": "create",
        "user": {"username": "system:serviceaccount:kube-system:operator"},
        "objectRef": {
          "resource": "clusterroles",
          "name": "operator-role"
        },
        "responseStatus": {"code": 201},
        "requestObject": {
          "kind": "ClusterRole",
          "rules": [
            {
              "apiGroups": ["*"],
              "resources": ["*"],
              "verbs": ["*"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit"
      }
  - Name: Failed request (excluded)
    ExpectedResult: false
    Log:
      {
        "kind": "Event",
        "verb": "create",
        "user": {"username": "attacker@example.com"},
        "objectRef": {
          "resource": "clusterroles",
          "name": "wildcard-role"
        },
        "responseStatus": {"code": 403},
        "requestObject": {
          "kind": "ClusterRole",
          "rules": [
            {
              "apiGroups": ["*"],
              "resources": ["*"],
              "verbs": ["*"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit"
      }
  - Name: Updating existing role (not creating)
    ExpectedResult: false
    Log:
      {
        "kind": "Event",
        "verb": "update",
        "user": {"username": "admin@example.com"},
        "objectRef": {
          "resource": "clusterroles",
          "name": "existing-role"
        },
        "responseStatus": {"code": 200},
        "requestObject": {
          "kind": "ClusterRole",
          "rules": [
            {
              "apiGroups": ["*"],
              "resources": ["*"],
              "verbs": ["*"]
            }
          ]
        },
        "p_log_type": "Amazon.EKS.Audit"
      }

# ------ paired body: k8s_role_wildcard.py ------

from panther_kubernetes_helpers import is_failed_request, is_system_principal, k8s_alert_context


def rule(event):
    verb = event.udm("verb")
    resource = event.udm("resource")
    username = event.udm("username")
    response_status = event.udm("responseStatus")

    # Only check Role/ClusterRole creation events
    if verb != "create" or resource not in {"roles", "clusterroles"}:
        return False

    # Skip failed requests
    if is_failed_request(response_status):
        return False

    # Exclude system principals to reduce false positives from legitimate operators
    if is_system_principal(username):
        return False

    # Check if role grants wildcard permissions
    request_object = event.udm("requestObject") or {}
    rules = request_object.get("rules") or []

    for rule_entry in rules:
        resources = rule_entry.get("resources") or []
        verbs = rule_entry.get("verbs") or []

        # Check for wildcard in resources or verbs
        if "*" in resources or "*" in verbs:
            return True

    return False


def title(event):
    username = event.udm("username") or "<UNKNOWN_USER>"
    resource = event.udm("resource") or "<UNKNOWN_RESOURCE>"
    name = event.udm("name") or "<UNKNOWN_ROLE>"
    namespace = event.udm("namespace") or "<CLUSTER_SCOPED>"

    role_type = "ClusterRole" if resource == "clusterroles" else "Role"

    if namespace != "<CLUSTER_SCOPED>":
        return f"[{username}] created {role_type} [{namespace}/{name}] with wildcard permissions"

    return f"[{username}] created {role_type} [{name}] with wildcard permissions "


def dedup(event):
    username = event.udm("username") or "<UNKNOWN_USER>"
    resource = event.udm("resource") or "<UNKNOWN_RESOURCE>"
    name = event.udm("name") or "<UNKNOWN_ROLE>"
    return f"k8s_role_wildcard_{username}_{resource}_{name}"


def severity(event):
    """ClusterRoles with wildcards are more dangerous than namespaced Roles."""
    resource = event.udm("resource") or ""

    # Critical for ClusterRole (cluster-wide wildcard permissions)
    if resource == "clusterroles":
        return "CRITICAL"

    # High for namespaced Role (namespace-scoped wildcard permissions)
    return "HIGH"


def alert_context(event):
    request_object = event.udm("requestObject") or {}
    rules = request_object.get("rules") or []

    # Extract only the rules that contain wildcards
    wildcard_rules = []
    for rule_entry in rules:
        resources = rule_entry.get("resources") or []
        verbs = rule_entry.get("verbs") or []
        if "*" in resources or "*" in verbs:
            wildcard_rules.append(rule_entry)

    return k8s_alert_context(
        event,
        extra_fields={
            "role_name": event.udm("name"),
            "role_type": event.udm("resource"),
            "wildcard_rules": wildcard_rules,
        },
    )

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.