Detection rules › Elastic

Direct Interactive Kubernetes API Request by Unusual Utilities

Status
production
Severity
low
Time window
1s
Sequence by
kubernetes.audit.user.extra.authentication.kubernetes.io/pod-name, orchestrator.resource.name
Author
Elastic
Source
github.com/elastic/detection-rules

This rule leverages a combination of Defend for Containers and Kubernetes audit logs to detect the execution of direct interactive Kubernetes API requests via unusual utilities. An adversary may need to execute direct interactive Kubernetes API requests to gain access to the Kubernetes API server or other resources within the cluster. These requests are often used to enumerate the Kubernetes API server or other resources within the cluster, and may indicate an attempt to move laterally within the cluster.

Known false positives

  • There is a potential for false positives if the direct interactive Kubernetes API requests are used for legitimate purposes, such as debugging or troubleshooting. It is important to investigate any alerts generated by this rule to determine if they are indicative of malicious activity or part of legitimate container activity.
  • There is a risk of false positives if there are several containers named the same, as the rule may correlate the request to the wrong container.

MITRE ATT&CK coverage

Telemetry coverage

PlatformRecord / event type
Kubernetesget-clusterrolebindings: get clusterrolebindings
Kuberneteslist-clusterrolebindings: list clusterrolebindings
Kuberneteswatch-clusterrolebindings: watch clusterrolebindings
Kubernetescreate-clusterrolebindings: create clusterrolebindings
Kubernetesupdate-clusterrolebindings: update clusterrolebindings
Kubernetespatch-clusterrolebindings: patch clusterrolebindings
Kubernetesget-clusterroles: get clusterroles
Kuberneteslist-clusterroles: list clusterroles
Kuberneteswatch-clusterroles: watch clusterroles
Kubernetescreate-clusterroles: create clusterroles
Kubernetesupdate-clusterroles: update clusterroles
Kubernetespatch-clusterroles: patch clusterroles
Kubernetesget-configmaps: get configmaps
Kuberneteslist-configmaps: list configmaps
Kuberneteswatch-configmaps: watch configmaps
Kubernetescreate-configmaps: create configmaps
Kubernetesupdate-configmaps: update configmaps
Kubernetespatch-configmaps: patch configmaps
Kubernetesget-cronjobs: get cronjobs
Kuberneteslist-cronjobs: list cronjobs
Kuberneteswatch-cronjobs: watch cronjobs
Kubernetescreate-cronjobs: create cronjobs
Kubernetesupdate-cronjobs: update cronjobs
Kubernetespatch-cronjobs: patch cronjobs
Kubernetesget-daemonsets: get daemonsets
Kuberneteslist-daemonsets: list daemonsets
Kuberneteswatch-daemonsets: watch daemonsets
Kubernetescreate-daemonsets: create daemonsets
Kubernetesupdate-daemonsets: update daemonsets
Kubernetespatch-daemonsets: patch daemonsets
Kubernetesget-deployments: get deployments
Kuberneteslist-deployments: list deployments
Kuberneteswatch-deployments: watch deployments
Kubernetescreate-deployments: create deployments
Kubernetesupdate-deployments: update deployments
Kubernetespatch-deployments: patch deployments
Kubernetesget-jobs: get jobs
Kuberneteslist-jobs: list jobs
Kuberneteswatch-jobs: watch jobs
Kubernetescreate-jobs: create jobs
Kubernetesupdate-jobs: update jobs
Kubernetespatch-jobs: patch jobs
Kubernetesget-namespaces: get namespaces
Kuberneteslist-namespaces: list namespaces
Kuberneteswatch-namespaces: watch namespaces
Kubernetescreate-namespaces: create namespaces
Kubernetesupdate-namespaces: update namespaces
Kubernetespatch-namespaces: patch namespaces
Kubernetesget-nodes: get nodes
Kuberneteslist-nodes: list nodes
Kuberneteswatch-nodes: watch nodes
Kubernetescreate-nodes: create nodes
Kubernetesupdate-nodes: update nodes
Kubernetespatch-nodes: patch nodes
Kubernetesget-pods: get pods
Kuberneteslist-pods: list pods
Kuberneteswatch-pods: watch pods
Kubernetescreate-pods: create pods
Kubernetesupdate-pods: update pods
Kubernetespatch-pods: patch pods
Kubernetesget-pods-attach: get pods/attach
Kubernetescreate-pods-attach: create pods/attach
Kubernetesget-pods-exec: get pods/exec
Kubernetescreate-pods-exec: create pods/exec
Kubernetesget-pods-log: get pods/log
Kubernetesget-pods-portforward: get pods/portforward
Kubernetescreate-pods-portforward: create pods/portforward
Kubernetesget-rolebindings: get rolebindings
Kuberneteslist-rolebindings: list rolebindings
Kuberneteswatch-rolebindings: watch rolebindings
Kubernetescreate-rolebindings: create rolebindings
Kubernetesupdate-rolebindings: update rolebindings
Kubernetespatch-rolebindings: patch rolebindings
Kubernetesget-roles: get roles
Kuberneteslist-roles: list roles
Kuberneteswatch-roles: watch roles
Kubernetescreate-roles: create roles
Kubernetesupdate-roles: update roles
Kubernetespatch-roles: patch roles
Kubernetesget-secrets: get secrets
Kuberneteslist-secrets: list secrets
Kuberneteswatch-secrets: watch secrets
Kubernetescreate-secrets: create secrets
Kubernetesupdate-secrets: update secrets
Kubernetespatch-secrets: patch secrets
Kubernetescreate-selfsubjectaccessreviews: create selfsubjectaccessreviews
Kubernetescreate-selfsubjectrulesreviews: create selfsubjectrulesreviews
Kubernetesget-serviceaccounts: get serviceaccounts
Kuberneteslist-serviceaccounts: list serviceaccounts
Kuberneteswatch-serviceaccounts: watch serviceaccounts
Kubernetescreate-serviceaccounts: create serviceaccounts
Kubernetesupdate-serviceaccounts: update serviceaccounts
Kubernetespatch-serviceaccounts: patch serviceaccounts
Kubernetesget-statefulsets: get statefulsets
Kuberneteslist-statefulsets: list statefulsets
Kuberneteswatch-statefulsets: watch statefulsets
Kubernetescreate-statefulsets: create statefulsets
Kubernetesupdate-statefulsets: update statefulsets
Kubernetespatch-statefulsets: patch statefulsets
Kubernetescreate-subjectaccessreviews: create subjectaccessreviews

Rules detecting the same action

These rules filter on the same operation.

Rule body

[metadata]
creation_date = "2026/01/21"
integration = ["cloud_defend", "kubernetes"]
maturity = "production"
min_stack_comments = "Defend for Containers integration was re-introduced in 9.3.0"
min_stack_version = "9.3.0"
updated_date = "2026/04/10"

[rule]
author = ["Elastic"]
description = """
This rule leverages a combination of Defend for Containers and Kubernetes audit logs to detect the execution of direct
interactive Kubernetes API requests via unusual utilities. An adversary may need to execute direct interactive Kubernetes
API requests to gain access to the Kubernetes API server or other resources within the cluster. These requests are often
used to enumerate the Kubernetes API server or other resources within the cluster, and may indicate an attempt to move
laterally within the cluster.
"""
false_positives = [
    """
    There is a potential for false positives if the direct interactive Kubernetes API requests are used for legitimate purposes,
    such as debugging or troubleshooting. It is important to investigate any alerts generated by this rule to determine
    if they are indicative of malicious activity or part of legitimate container activity.
    """,
    """
    There is a risk of false positives if there are several containers named the same, as the rule may correlate the request
    to the wrong container.
    """,
]
from = "now-6m"
index = ["logs-cloud_defend.process*", "logs-kubernetes.audit_logs-*"]
interval = "5m"
language = "eql"
license = "Elastic License v2"
name = "Direct Interactive Kubernetes API Request by Unusual Utilities"
note = """ ## Triage and analysis

> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.

### Investigating Direct Interactive Kubernetes API Request by Unusual Utilities

This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload.

### Possible investigation steps

- Identify the implicated pod, container image, and executing service account, then quickly review its RBAC bindings and effective permissions to determine blast radius.
- Inspect the container’s interactive session context by pulling recent command lines, shell history, environment variables, and mounted service account tokens, and look for custom scripts or binaries issuing HTTP requests.
- Correlate nearby Kubernetes audit entries tied to the same principal and pod to map accessed resources and verbs, noting any exec/attach/portforward or sensitive object interactions across namespaces.
- Review network activity from the pod to the API server and any in-pod proxies, including DNS lookups and outbound connections, to spot nonstandard clients or tunneling behavior.
- If suspicious, isolate the pod or node, capture runtime artifacts (e.g., process memory or HTTP client traffic), revoke and rotate the service account credentials, and verify image provenance and integrity.

### False positive analysis

- An operator interactively attaches to a pod and uses a Python REPL or bash with /dev/tcp to call the in-cluster API for routine troubleshooting (e.g., list pods, read ConfigMaps, or run selfsubjectaccessreviews), producing normal audit entries that match the rule signature.
- A correlation artifact arises when two namespaces have pods with the same name: one pod starts an interactive shell while another independently performs get/list/watch calls, and the 1-second sequence keyed only on pod-name links the unrelated events.

### Response and remediation

- Immediately isolate the implicated pod that issued direct API calls using a nonstandard utility by applying a deny-all egress NetworkPolicy in its namespace (including to kubernetes.default.svc:443), terminating the interactive session, and scaling its owning Deployment/Job/StatefulSet to zero replicas.
- Before teardown, capture a runtime snapshot of the container and node including the binary or script used to query the API (e.g., files under /tmp or /dev/tcp usage), shell history, environment, and the mounted service account token and CA bundle at /var/run/secrets/kubernetes.io/serviceaccount/.
- Revoke access by removing the service account’s RoleBindings/ClusterRoleBindings, deleting all pods that mount that service account to force token rotation, rotating any Secrets and ConfigMaps that were read or created during the window, and deleting any unauthorized Jobs, CronJobs, or Deployments created by the same principal.
- Restore workloads from a known-good image digest, re-enable the Deployment only after image scan and integrity checks pass, and monitor subsequent Kubernetes audit logs for pods/exec, portforward, and access to secrets across the affected namespaces.
- Escalate to incident response leadership and consider cluster-wide containment if audit logs show create/patch of ClusterRoleBindings, access to secrets outside the workload’s namespace, or use of pods/exec to pivot into other nodes or system namespaces such as kube-system.
- Harden access by enforcing least-privilege RBAC that denies pods/exec and attach for application service accounts, setting automountServiceAccountToken: false on workloads that do not need it, restricting egress to the API server with NetworkPolicies, and requiring just-in-time break-glass roles for interactive access.
"""
risk_score = 21
rule_id = "02275e05-57a1-46ab-a443-7fb444da6b28"
severity = "low"
tags = [
    "Data Source: Elastic Defend for Containers",
    "Data Source: Kubernetes",
    "Domain: Container",
    "Domain: Kubernetes",
    "OS: Linux",
    "Use Case: Threat Detection",
    "Tactic: Execution",
    "Tactic: Discovery",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"
query = '''
sequence with maxspan=1s
  [process where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.interactive == true and
  container.id like "*" and
  /* Covered by the rule "Direct Interactive Kubernetes API Request by Common Utilities" */
  not (
     process.name in ("wget", "curl", "openssl", "socat", "ncat", "kubectl") or
     (
       /* Account for tools that execute utilities as a subprocess, in this case the target utility name will appear as a process arg */
       process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
       process.args in (
         "wget", "/bin/wget", "/usr/bin/wget", "/usr/local/bin/wget",
         "ssl_client", "/bin/ssl_client", "/usr/bin/ssl_client", "/usr/local/bin/ssl_client",
         "curl", "/bin/curl", "/usr/bin/curl", "/usr/local/bin/curl",
         "openssl", "/bin/openssl", "/usr/bin/openssl", "/usr/local/bin/openssl",
         "socat", "/bin/socat", "/usr/bin/socat", "/usr/local/bin/socat",
         "ncat", "/bin/ncat", "/usr/bin/ncat", "/usr/local/bin/ncat",
         "kubectl", "/bin/kubectl", "/usr/bin/kubectl", "/usr/local/bin/kubectl"
       ) and
       /* default exclusion list to not FP on default multi-process commands */
       not process.args in (
         "which", "/bin/which", "/usr/bin/which", "/usr/local/bin/which",
         "man", "/bin/man", "/usr/bin/man", "/usr/local/bin/man",
         "chmod", "/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod",
         "chown", "/bin/chown", "/usr/bin/chown", "/usr/local/bin/chown"
       )
     ) or
     /* General exclusions for utilities that are not typically used for Kubernetes API requests */
     process.name in (
       "sleep", "head", "tail", "apk", "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf",
       "pacman", "rpm", "dpkg"
     )
   )] by orchestrator.resource.name
  [any where
     data_stream.dataset == "kubernetes.audit_logs" and
     kubernetes.audit.stage in ("ResponseStarted","ResponseComplete") and
     kubernetes.audit.verb in ("get", "list", "watch", "create", "patch", "update") and
     (
       kubernetes.audit.objectRef.resource in (
         "pods", "secrets", "serviceaccounts", "configmaps",
         "roles", "rolebindings", "clusterroles", "clusterrolebindings",
         "deployments", "daemonsets", "statefulsets", "jobs", "cronjobs",
         "nodes", "namespaces",
         "selfsubjectaccessreviews", "selfsubjectrulesreviews", "subjectaccessreviews"
       )
       or (
         kubernetes.audit.objectRef.resource == "pods" and
         kubernetes.audit.objectRef.subresource in ("exec", "attach", "portforward", "log")
       )
     )
  ] by `kubernetes.audit.user.extra.authentication.kubernetes.io/pod-name`
'''

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"

[[rule.threat.technique.subtechnique]]
id = "T1059.004"
name = "Unix Shell"
reference = "https://attack.mitre.org/techniques/T1059/004/"

[[rule.threat.technique]]
id = "T1609"
name = "Container Administration Command"
reference = "https://attack.mitre.org/techniques/T1609/"

[[rule.threat.technique]]
id = "T1610"
name = "Deploy Container"
reference = "https://attack.mitre.org/techniques/T1610/"

[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1069"
name = "Permission Groups Discovery"
reference = "https://attack.mitre.org/techniques/T1069/"

[[rule.threat.technique]]
id = "T1087"
name = "Account Discovery"
reference = "https://attack.mitre.org/techniques/T1087/"

[[rule.threat.technique]]
id = "T1613"
name = "Container and Resource Discovery"
reference = "https://attack.mitre.org/techniques/T1613/"

[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"

Stages and Predicates

Ordered sequence: each step below must occur in order within 1s, correlated by kubernetes.audit.user.extra.authentication.kubernetes.io/pod-name, orchestrator.resource.name.

Stage 1: process

[process where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.interactive == true and
  container.id like "*" and
  not (
     process.name in ("wget", "curl", "openssl", "socat", "ncat", "kubectl") or
     (
       process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
       process.args in (
         "wget", "/bin/wget", "/usr/bin/wget", "/usr/local/bin/wget",
         "ssl_client", "/bin/ssl_client", "/usr/bin/ssl_client", "/usr/local/bin/ssl_client",
         "curl", "/bin/curl", "/usr/bin/curl", "/usr/local/bin/curl",
         "openssl", "/bin/openssl", "/usr/bin/openssl", "/usr/local/bin/openssl",
         "socat", "/bin/socat", "/usr/bin/socat", "/usr/local/bin/socat",
         "ncat", "/bin/ncat", "/usr/bin/ncat", "/usr/local/bin/ncat",
         "kubectl", "/bin/kubectl", "/usr/bin/kubectl", "/usr/local/bin/kubectl"
       ) and
       not process.args in (
         "which", "/bin/which", "/usr/bin/which", "/usr/local/bin/which",
         "man", "/bin/man", "/usr/bin/man", "/usr/local/bin/man",
         "chmod", "/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod",
         "chown", "/bin/chown", "/usr/bin/chown", "/usr/local/bin/chown"
       )
     ) or
     process.name in (
       "sleep", "head", "tail", "apk", "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf",
       "pacman", "rpm", "dpkg"
     )
   )] by orchestrator.resource.name

Stage 2: any

[any where
     data_stream.dataset == "kubernetes.audit_logs" and
     kubernetes.audit.stage in ("ResponseStarted","ResponseComplete") and
     kubernetes.audit.verb in ("get", "list", "watch", "create", "patch", "update") and
     (
       kubernetes.audit.objectRef.resource in (
         "pods", "secrets", "serviceaccounts", "configmaps",
         "roles", "rolebindings", "clusterroles", "clusterrolebindings",
         "deployments", "daemonsets", "statefulsets", "jobs", "cronjobs",
         "nodes", "namespaces",
         "selfsubjectaccessreviews", "selfsubjectrulesreviews", "subjectaccessreviews"
       )
       or (
         kubernetes.audit.objectRef.resource == "pods" and
         kubernetes.audit.objectRef.subresource in ("exec", "attach", "portforward", "log")
       )
     )
  ] by `kubernetes.audit.user.extra.authentication.kubernetes.io/pod-name`

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.argsin/bin/chmod, /bin/chown, /bin/man, /bin/which, /usr/bin/chmod, /usr/bin/chown, /usr/bin/man, /usr/bin/which, /usr/local/bin/chmod, /usr/local/bin/chown, /usr/local/bin/man, /usr/local/bin/which, chmod, chown, man, whichexcludes:process.args
process.argsin/bin/curl, /bin/kubectl, /bin/ncat, /bin/openssl, /bin/socat, /bin/ssl_client, /bin/wget, /usr/bin/curl, /usr/bin/kubectl, /usr/bin/ncat, /usr/bin/openssl, /usr/bin/socat, /usr/bin/ssl_client, /usr/bin/wget, /usr/local/bin/curl, /usr/local/bin/kubectl, /usr/local/bin/ncat, /usr/local/bin/openssl, /usr/local/bin/socat, /usr/local/bin/ssl_client, /usr/local/bin/wget, curl, kubectl, ncat, openssl, socat, ssl_client, wgetexcludes:process.args
process.nameinbash, busybox, csh, dash, fish, ksh, sh, tcsh, zshexcludes:process.name
process.nameinapk, apt, apt-get, dnf, dpkg, head, microdnf, pacman, rpm, sleep, tail, tdnf, yum, zypperexcludes:process.name
process.nameincurl, kubectl, ncat, openssl, socat, wgetexcludes:process.name

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
container.idwildcard
  • *
field:"container.id" kind:wildcard value:"*"
data_stream.dataseteq
  • kubernetes.audit_logs
field:"data_stream.dataset" kind:eq value:"kubernetes.audit_logs"
event.actioneq
  • exec
field:"EventType" kind:eq value:"exec"
event.typeeq
  • start
field:"event.type" kind:eq value:"start"
kubernetes.audit.objectRef.resourceeq
  • pods
field:"kubernetes.audit.objectRef.resource" kind:eq value:"pods"
kubernetes.audit.objectRef.resourcein
  • clusterrolebindings
  • clusterroles
  • configmaps
  • cronjobs
  • daemonsets
  • deployments
  • jobs
  • namespaces
  • nodes
  • pods
  • rolebindings
  • roles
  • secrets
  • selfsubjectaccessreviews
  • selfsubjectrulesreviews
  • serviceaccounts
  • statefulsets
  • subjectaccessreviews
field:"kubernetes.audit.objectRef.resource" kind:in
kubernetes.audit.objectRef.subresourcein
  • attach
  • exec
  • log
  • portforward
field:"kubernetes.audit.objectRef.subresource" kind:in
kubernetes.audit.stagein
  • ResponseComplete
  • ResponseStarted
field:"kubernetes.audit.stage" kind:in
kubernetes.audit.verbin
  • create
  • get
  • list
  • patch
  • update
  • watch
field:"kubernetes.audit.verb" kind:in
process.argsin
  • /bin/chmod
  • /bin/chown
  • /bin/man
  • /bin/which
  • /usr/bin/chmod
  • /usr/bin/chown
  • /usr/bin/man
  • /usr/bin/which
  • /usr/local/bin/chmod
  • /usr/local/bin/chown
  • /usr/local/bin/man
  • /usr/local/bin/which
  • chmod
  • chown
  • man
  • which
field:"process.args" kind:in
process.interactiveeq
  • true transforms: boolean
field:"process.interactive" kind:eq value:"true"