T1098.006

Additional Container Cluster Roles

An adversary may add additional roles or permissions to an adversary-controlled user or service account to maintain persistent access to a container orchestration system. For example, an adversary with sufficient permissions may create a RoleBinding or ClusterRoleBinding to bind a Role or ClusterRole to a Kubernetes account. Where ABAC is in use, an adversary may modify a Kubernetes ABAC policy to give the target account additional permissions. This technique may also be used in conjunction with cloud-based RBAC assignments in managed Kubernetes services such as GKE, EKS, and AKS.

Microsoft Sentinel / Defender
kusto
// Detect creation or modification of Kubernetes RBAC bindings and privilege escalation in container clusters
// Covers Azure Kubernetes Service (AKS) via AzureActivity and AzureDiagnostics, plus Defender for Containers
let SuspiciousRBACOperations = dynamic([
  "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/clusterrolebindings/write",
  "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/rolebindings/write",
  "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/clusterroles/write",
  "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/roles/write"
]);
let HighPrivilegeRoles = dynamic([
  "cluster-admin", "admin", "edit", "system:masters"
]);
// AKS Control Plane Audit Logs
AzureDiagnostics
| where TimeGenerated > ago(24h)
| where Category == "kube-audit" or Category == "kube-audit-admin"
| extend LogEntry = parse_json(log_s)
| extend
    Verb = tostring(LogEntry.verb),
    Resource = tostring(LogEntry.objectRef.resource),
    ResourceName = tostring(LogEntry.objectRef.name),
    Namespace = tostring(LogEntry.objectRef.namespace),
    UserName = tostring(LogEntry.user.username),
    UserGroups = tostring(LogEntry.user.groups),
    SourceIP = tostring(LogEntry.sourceIPs[0]),
    UserAgent = tostring(LogEntry.userAgent),
    RequestURI = tostring(LogEntry.requestURI),
    ResponseCode = toint(LogEntry.responseStatus.code)
| where Verb in ("create", "update", "patch")
| where Resource in ("clusterrolebindings", "rolebindings", "clusterroles", "roles")
| where ResponseCode between (200 .. 299)
| extend RequestObject = tostring(LogEntry.requestObject)
| extend IsSensitiveRole = RequestObject has_any (HighPrivilegeRoles)
| extend IsServiceAccount = UserName startswith "system:serviceaccount:"
| extend IsSystemUser = UserName startswith "system:"
| where not (IsSystemUser and not IsServiceAccount)
| project
    TimeGenerated,
    Verb,
    Resource,
    ResourceName,
    Namespace,
    UserName,
    UserGroups,
    SourceIP,
    UserAgent,
    IsSensitiveRole,
    IsServiceAccount,
    RequestObject,
    ResponseCode,
    ResourceId
| sort by TimeGenerated desc
high severity medium confidence

Data Sources

Azure Kubernetes Service Audit Logs AzureDiagnostics (kube-audit category) Azure Activity Logs

Required Tables

AzureDiagnostics AzureActivity

False Positives

  • Legitimate cluster administrators creating or updating RBAC bindings as part of normal operations or infrastructure-as-code deployments (Terraform, Helm, ArgoCD)
  • CI/CD pipelines (GitHub Actions, Jenkins, GitLab CI) that apply RBAC manifests during application deployment
  • Kubernetes operators and controllers (e.g., cert-manager, Prometheus operator) that create their own service account role bindings during installation
  • Cluster upgrades or managed add-on installations by the cloud provider that temporarily create or modify RBAC objects

Unlock Pro Content

Get the full detection package for T1098.006 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections