What the Kubernetes audit log tells you
Every request to the Kubernetes API server — from kubectl, controllers, kubelets or a stolen token — can be recorded as an audit event: who (user, groups, service account), from where (source IPs, user agent), what (verb, resource, namespace, name, subresource), whether it was allowed and why (the RBAC binding), and at higher levels the request body itself.
That makes it the primary evidence to answer "was our cluster compromised?": a stolen service-account token, a privileged pod mounting the node, a new cluster-admin binding or a crypto-miner CronJob all leave API calls behind, even when the workloads themselves are gone.
What this tool detects
- Execution: pods/exec and pods/attach (especially by service accounts), port-forward, kubelet access through nodes/proxy.
- Credential access: secrets listed across all namespaces, bursts of secret reads, service-account tokens minted with TokenRequest.
- Privilege escalation and container escape: privileged containers, hostPID/hostNetwork/hostIPC, hostPath mounts of / or runtime sockets, DaemonSets in kube-system.
- RBAC abuse: new bindings to cluster-admin, roles with escalate/bind/impersonate or wildcards, impersonation, access granted to anonymous users.
- Recon: kubectl auth can-i bursts (SelfSubjectAccessReviews / RulesReviews), bursts of 403s, service-account tokens used with kubectl or curl or from public IPs, known attack-tool user agents.
- Impact and persistence: crypto-miner images and commands, images from unusual registries, CronJobs, deleted Kubernetes events. Optional Falco alerts are correlated on the same timeline.
- Detections are data: a reviewed JSON rule file (Sigma-like conditions) mapped to the MITRE ATT&CK Containers matrix, so they can be read, audited and reused.
How to export Kubernetes audit logs
Audit logging must be enabled before an incident to be useful. Export the whole period of interest (ideally a few days before the first suspicious event) as JSON; gzip and ZIP are fine.
Self-managed (kubeadm, k3s, RKE2, on-prem)
- The API server writes audit events when started with --audit-policy-file and --audit-log-path (for example /var/log/kubernetes/audit/audit.log).
- On each control-plane node, copy the current audit.log and its rotated files (audit-*.log, possibly .gz).
- If you ship audit events with the webhook backend (Fluent Bit, Vector, a SIEM), export them from there as JSON lines.
- Drop the files or the whole folder here.
Amazon EKS
- Control-plane logging must include the "audit" log type (EKS console → cluster → Observability → Control plane logging).
- Events are in CloudWatch Logs, log group /aws/eks/<cluster>/cluster, streams kube-apiserver-audit-*.
- Small ranges: aws logs filter-log-events --log-group-name /aws/eks/<cluster>/cluster --log-stream-name-prefix kube-apiserver-audit --start-time <ms> --end-time <ms> > eks-audit.json
- Large ranges: create an export task to S3 (aws logs create-export-task), download the .gz files and drop the folder. CloudWatch Logs Insights results exported as JSON also work.
Google GKE
- Admin Activity audit logs are always on; Data Access logs (get/list, secret reads) must be enabled for the Kubernetes Engine API in IAM → Audit Logs.
- Export with gcloud: gcloud logging read 'resource.type="k8s_cluster" AND logName:"cloudaudit.googleapis.com"' --project=<project> --freshness=30d --format=json > gke-audit.json
- Or download the results from Logs Explorer as JSON, or use a log sink to Cloud Storage / BigQuery for long periods (export BigQuery rows as JSON or newline-delimited JSON).
- Drop the JSON files here; entries from other services are ignored.
Azure AKS
- Create a diagnostic setting on the cluster with the kube-audit (or kube-audit-admin, which excludes get/list) category.
- Storage account destination: download the PT1H.json blobs under insights-logs-kube-audit/… and drop the folder.
- Log Analytics destination: query AKSAudit (or AzureDiagnostics | where Category startswith "kube-audit") and export the results as JSON, not CSV.
- Event Hubs exports ({"records": […]}) are supported too.
Make sure the evidence exists
- Log at least Metadata for everything, and Request or RequestResponse for RBAC objects, pods, workloads, pods/exec and serviceaccounts/token: without request bodies, privileged pods and cluster-admin bindings cannot be recognised.
- Never log secrets, configmaps or tokenreviews bodies (Metadata only): the log would become a credential store.
- Keep audit logs outside the cluster, for at least 90 days: attackers with cluster-admin can tamper with anything inside it.
Limitations
- The audit log only sees the API server: activity inside a container or on a node (a reverse shell, a miner started by hand) is invisible without runtime tools such as Falco.
- What is detected depends on your audit policy: at Metadata level, request bodies (privileged flags, images, roleRef) are missing and several detections cannot fire.
- Rules flag patterns, not intent: legitimate admins also run kubectl exec, and operators create DaemonSets. Every finding needs a human review.
- Only JSON exports are read (CSV exports are not supported yet). Service-account names of your own platform components may need to be added to the rule allow-lists.
FAQ
Are my audit logs uploaded anywhere?
No. The analyzer is Rust compiled to WebAssembly and runs in a Web Worker in your browser; files are streamed from your disk in chunks. There is no upload endpoint.
How large an export can it handle?
Files are read and decompressed as a stream, so size is limited mostly by time: expect tens to a few hundred MB per minute depending on your machine. Small exports keep every event browsable; above 50,000 events only flagged events are kept, while counts, entities and findings still cover everything.
Which formats are supported?
Raw audit.k8s.io/v1 JSON lines, EKS CloudWatch exports (filter-log-events, Logs Insights JSON, S3 export files), GKE Cloud Logging JSON (gcloud logging read, Logs Explorer downloads, sinks), AKS diagnostic logs (storage account, Event Hubs, AKSAudit / AzureDiagnostics JSON), gzip and ZIP, plus Falco JSON alerts.
How do I detect kubectl exec in audit logs?
kubectl exec creates a request on the pods/exec subresource (verb create or get, objectRef.subresource exec); the command is in the requestURI as command= parameters. This tool lists every exec, attach and port-forward, and raises the severity when a service account does it.
Does "No sign of compromise" mean we are safe?
No. It means none of the rules matched in the logs you provided. Gaps in the audit policy, missing time ranges and in-container activity can all hide an intrusion. If you have other reasons to worry, get an expert review.
Can I see or reuse the detection rules?
Yes. They are a JSON file in the open repository (crates/k8s-audit-wasm/rules), with conditions, thresholds, MITRE ATT&CK technique ids and remediation steps, so they can be reviewed and reused in other tools.