Skip to content

Back to the catalog

AWS EKS Forensics: Data Sources and Investigation Tooling
synacktiv.comarticle

AWS EKS Forensics: Data Sources and Investigation Tooling

Synacktiv's CSIRT breaks down the forensic data sources exposed by Amazon EKS across three layers — Kubernetes control plane (audit logs), data plane (Container Insights/Fluent Bit), and AWS services (GuardDuty EKS Protection, CloudTrail) — and provides concrete CloudWatch Logs Insights queries for RBAC-escalation detection, static pod persistence, node credential theft, and other attack indicators. It also covers node-level acquisition (SSM, kubectl debug), containment pitfalls that destroy evidence, and a full investigation workflow from GuardDuty finding to cross-layer timeline correlation.

TL;DR A practical playbook for investigating AWS EKS compromises using audit logs, Container Insights, GuardDuty, and CloudTrail, with ready-to-use CloudWatch Logs Insights queries for RBAC escalation, static pod persistence, and stolen node/pod identities.
Document

What it is

A field guide from Synacktiv's CSIRT to what an EKS compromise leaves behind and how to pull it back out of AWS-native telemetry. The summary already names the three log layers and the general query targets; below are the concrete commands, detection tells, and constraints the summary cannot carry.

Preconditions

Compute mode decides node access and is the first triage step: standard clusters run worker nodes as EC2 instances reachable via SSH/SSM; under Auto Mode or Fargate the host is AWS-managed and direct node access is unavailable. Almost nothing is logged by default — control plane logs are off, Container Insights and GuardDuty Runtime Monitoring are opt-in — so the investigation's outcome is largely fixed before the incident.

What to do

Enable all five control-plane log types (all land in /aws/eks/[cluster]/cluster):

aws eks update-cluster-config --name <cluster> --region <region> \
  --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'

Static-pod persistence is the page's marquee detection. On EKS-optimized AMIs the kubelet does not watch a manifests dir by default (staticPodPath absent from /etc/kubernetes/kubelet/config.json), so an attacker must set it and restart the service — an artifact observable on the node before any pod event. The kubelet registers a mirror pod (visible to kubectl) and GuardDuty raises Execution:Kubernetes/AnomalousBehavior.WorkloadDeployed. The conclusive audit-log tell is a pod created by a system:node: identity carrying annotation kubernetes.io/config.source = "file" (vs "api"):

fields @timestamp, user.username, objectRef.name,
       `requestObject.metadata.annotations.kubernetes.io/config.source` as config_source
| filter verb = "create" and objectRef.resource = "pods"
| filter user.username like "system:node:"
| sort @timestamp desc

Node-local token theft — projected ServiceAccount tokens of pods scheduled on a node are a common target:

find /var/lib/kubelet/pods -path "*/kubernetes.io~projected/*/token" -type f

Node acquisition: prefer aws ssm start-session --target [node instance-id]. Fall back to kubectl debug node/[node] only as last resort — it schedules a workload on the node under examination and leaves fresh create pods entries in the audit log; use deliberately and document it.

Containment ordering matters: kubectl delete destroys process state, the writable upper layer, and projected tokens the analysis depends on, and a controller may reschedule the workload. Isolate at the network layer (NetworkPolicies, Security Groups) while keeping liveness/readiness probes satisfied so the pod is neither killed nor moved. But network isolation does not stop a stolen AWS identity — a node-role or ServiceAccount token replays from anywhere, so revoke/rotate those credentials.

Caveats

  • GuardDuty is a black box: detection rules are undisclosed and non-extensible; a finding is a lead, never a verdict. Runtime Monitoring (eBPF syscall visibility) is optional, adds pods, and is unsupported on Fargate — without it, in-container command execution is the coverage gap that only a third-party agent fills.
  • Kubelet checkpoint API (CRIU-based, Beta since v1.30) is not usable on EKS as of writing — the EKS-optimized AMIs do not ship CRIU in the CRI runtime.
  • Third-party runtime tools (Falco, Sysdig, Wiz) are explicitly out of scope.

Organisations named here

  • Execution:Kubernetes/AnomalousBehavior.WorkloadDeployed
  • Synacktiv

Technologies named here

  • Amazon EKS
  • CloudWatch Logs Insights
  • EKS worker nodes
  • Amazon GuardDuty
  • AWS CloudTrail
  • EKS-optimized AMIs
  • kubectl
  • AWS Fargate
  • kubectl debug node/[node]
  • AWS SSM Session Manager
  • Amazon CloudWatch / CloudWatch Logs Insights
  • amazon-cloudwatch-observability EKS add-on
  • IAM
  • Fluent Bit
  • Kubernetes kubelet checkpoint API
  • CloudWatch agent
  • Falco
  • Argo CD
  • Sysdig
  • Wiz
  • CRIU
  • AWS
  • Kubernetes
  • AWS GuardDuty
  • AWS CloudWatch

Techniques named here

  • Helm template injection via GitOps controller
  • RBAC reconnaissance
  • RBAC privilege escalation via 'escalate' verb
  • Pod Security Admission evasion
  • Node account self-permission evaluation
  • Privileged container abuse
  • Sensitive host path mount
  • Reverse shell execution
  • Instance credential exfiltration
  • ServiceAccount token theft
  • Static pod persistence
  • Anomalous workload deployment
  • Container checkpointing
  • Cloud-resource discovery from stolen token
  • PrivilegeEscalation:Kubernetes/PrivilegedContainer
  • Persistence:Kubernetes/ContainerWithSensitiveMount
  • Execution:Runtime/ReverseShell

Also named here

  • UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS